Verwendung eines Wörterbuchs gegen Tupel in Python

31

Das konkrete Beispiel ist eine Liste der Dateinamen und ihrer Größen. Ich kann mich nicht entscheiden, ob jedes Element in der Liste die Form haben {"filename": "blabla", "size": 123}soll oder nur ("blabla", 123). Ein Wörterbuch erscheint mir logischer, weil der Zugriff auf die Größe zum Beispiel file["size"]erklärender ist als file[1]... aber ich weiß es nicht genau. Gedanken?

clb
quelle
Als Ergänzung sollten Sie das Entpacken von Tupeln in Betracht ziehen , wenn Sie sich Gedanken über die Lesbarkeit von Tupeln machen - fname, file_size = filewenn Daten das oben genannte Tupel sind, sollten Sie sie beseitigen file[1]und durch ersetzen file_size. Dies setzt natürlich eine gute Dokumentation voraus.
nlsdfnbch
2
Es hängt davon ab, welche Datenstruktur Sie erstellen und wie Sie darauf zugreifen möchten. (nach Dateiname? nach Index? beides?) Handelt es sich nur um eine wegwerfbare Variablen- / Datenstruktur, oder fügen Sie möglicherweise andere Elemente (/ Attribute) sowie die Größe hinzu? Muss sich die Struktur an eine Bestellung erinnern? Möchten Sie die Liste der Größen sortieren oder nach Position abrufen (z. B. "Top-n größte / kleinste Dateien")? Abhängig davon könnte die beste Antwort dict, OrderedDict, namedtuple, eine einfache alte Liste oder eine eigene Klasse sein. Benötigen Sie mehr Kontext von Ihnen.
smci

Antworten:

78

Ich würde ein verwenden namedtuple:

from collections import namedtuple
Filesize = namedtuple('Filesize', 'filename size')
file = Filesize(filename="blabla", size=123)

Jetzt können Sie file.sizeund file.filenamein Ihrem Programm verwenden, was meiner Meinung nach die am besten lesbare Form ist. Note namedtupleerstellt unveränderliche Objekte wie Tupel und diese sind leichter als Wörterbücher, wie hier beschrieben .

Doc Brown
quelle
1
Vielen Dank, gute Idee, ich habe bis heute noch nie von ihnen gehört (ich bin ziemlich neu bei Python). Frage: Was passiert, wenn jemand anders im Code dieselbe "Klasse" definiert, möglicherweise etwas anders. Filesize = namedtuple('Filesize', 'filepath kilobytes')
ZB
Sie können auch das sehr nette attrsModul verwenden (können es finden pipoder nur danach suchen), mit dem Sie dem genannten Tupel sehr ähnliche syntaktische Bequemlichkeiten bieten können, aber Sie können die Veränderbarkeit angeben (können aber auch unveränderlich gemacht werden). Der wesentliche funktionale Unterschied besteht darin, dass selbst attrserstellte Klassen nicht mit einfachen Tupeln verglichen werden können, wie es bei namedtuples der Fall ist .
mtraceur
3
@DocBrown Python kennt keine Deklarationskonzepte. class, defUnd =alle überschreiben nur alle früheren Verwendungen. repl.it
Challenger5
@ Challenger5: Du hast recht, mein Fehler, daher lautet die richtige Antwort: Es zählt die neueste Definition, kein Fehler aus der Python-Laufzeit, aber dennoch ähnliches Verhalten wie bei jeder anderen Variablen.
Doc Brown
8
Beachten Sie, dass dies namedtupleim Wesentlichen eine Kurzdeklaration für einen neuen Typ mit unveränderlichen Attributen ist. Das heißt, die Antwort lautet effektiv "Weder ein tuplenoch ein dict, sondern ein object." +1
jpmc26
18

{"filename": "blabla", "size": 123} oder einfach ("blabla", 123)

Dies ist die uralte Frage, ob Sie Ihr Format / Schema bandintern oder bandextern codieren möchten.

Sie tauschen etwas Speicher aus, um die Lesbarkeit und Portabilität zu erhalten, die sich aus dem Ausdruck des Formats der Daten direkt in den Daten ergibt. Wenn Sie dies nicht tun, müssen Sie wissen, dass das erste Feld der Dateiname und das zweite die Größe ist. Das spart Speicherplatz, kostet aber Lesbarkeit und Portabilität. Was kostet Ihr Unternehmen mehr Geld?

Denken Sie daran, dass unveränderliche Inhalte angesichts von Veränderungen nicht nutzlos sind. Dies bedeutet, dass wir mehr Speicherplatz benötigen, die Änderungen in einer Kopie vornehmen und die neue Kopie verwenden müssen. Das ist nicht kostenlos, aber es ist oft kein Deal Breaker. Wir verwenden unveränderliche Zeichenfolgen, um die Dinge ständig zu ändern.

Eine weitere Überlegung ist die Erweiterbarkeit. Wenn Sie Daten nur in Position speichern, ohne Formatinformationen zu verschlüsseln, sind Sie nur zur einmaligen Vererbung verurteilt. Dies ist in Wirklichkeit nichts anderes als die Praxis, zusätzliche Felder nach den festgelegten Feldern zu verketten. Ich kann ein drittes Feld als Erstellungsdatum definieren und trotzdem mit Ihrem Format kompatibel sein, da ich das erste und das zweite Feld auf die gleiche Weise definiere.

Was ich jedoch nicht tun kann, ist, zwei unabhängig definierte Formate zusammenzuführen, die einige überlappende Felder haben, andere nicht, sie in einem Format zu speichern und für Dinge nützlich zu sein, die nur das eine oder andere Format kennen.

Dazu muss ich die Formatinformationen von Anfang an codieren. Ich muss sagen "Dieses Feld ist der Dateiname". Dies ermöglicht eine mehrfache Vererbung.

Vermutlich sind Sie daran gewöhnt, dass Vererbung nur im Kontext von Objekten ausgedrückt wird, aber für Datenformate funktionieren dieselben Ideen, da Objekte in Datenformaten gespeichert werden. Es ist genau das gleiche Problem.

Verwenden Sie also, was Sie am ehesten benötigen. Ich greife nach Flexibilität, es sei denn, ich kann auf einen guten Grund hinweisen, dies nicht zu tun.

kandierte_orange
quelle
3
Um ehrlich zu sein, bezweifle ich, dass jemand, der sich nicht sicher ist, ob er ein In-Band- oder ein Out-of-Band-Format verwendet, so hohe Leistungsanforderungen hat, dass er ein Out-of-Band-Format verwenden müsste.
Alexander - Reinstate Monica
2
@ Alexander sehr wahr. Ich bevorzuge es, die Leute darüber zu unterrichten, damit sie verstehen, worauf sie schauen, wenn sie mit Out-of-Band-Lösungen konfrontiert werden. Binärformate tun dies häufig aus Verschleierungsgründen. Nicht jeder möchte portabel sein. Wenn es aus Performancegründen wirklich darauf ankommt, sollten Sie die Komprimierung in Betracht ziehen, bevor Sie auf Out-of-Band zurückgreifen.
candied_orange
Denken Sie daran, dass OP Python verwendet, sodass sie sich wahrscheinlich nicht allzu sehr um die Leistung kümmern. Der meiste Code auf hoher Ebene sollte zuerst mit Blick auf die Lesbarkeit geschrieben werden. Vorzeitige Optimierung ist die Wurzel allen Übels.
Dagrooms
@Dagrooms hassen Python nicht. Es funktioniert in vielen Fällen gut. Ansonsten stimme ich allem zu, was Sie gesagt haben. Mein Punkt war zu sagen "Deshalb machen die Leute das. Deshalb ist es dir wahrscheinlich egal".
candied_orange
@CandiedOrange Ich hasse die Sprache nicht, ich benutze sie in meiner täglichen Arbeit. Ich mag es nicht, wie die Leute es benutzen.
Dagrooms
7

Ich würde eine Klasse mit zwei Eigenschaften verwenden. file.sizeist schöner als entweder file[1]oder file["size"].

Einfach ist besser als komplex.

JacquesB
quelle
Falls sich jemand wundert: Zum Generieren von JSONs funktionieren beide gleich gut: file = Filesize(filename='stuff.txt', size=222)und filetup = ("stuff.txt", 222)beide generieren denselben JSON: json.dumps(file)und json.dumps(filetup)führen zu:'["stuff.txt", 222]'
Juha Untinen
5

Sind die Dateinamen eindeutig? In diesem Fall könnten Sie die Liste komplett löschen und einfach ein reines Wörterbuch für alle Dateien verwenden. zB (eine hypothetische Website)

{ 
  "/index.html" : 5467,
  "/about.html" : 3425,
  "/css/main.css" : 9876
}

etc...

Jetzt erhalten Sie nicht "Name" und "Größe", Sie verwenden nur Schlüssel und Wert, aber oft ist dies natürlicher. YMMV.

Wenn Sie aus Gründen der Übersichtlichkeit wirklich eine "Größe" wünschen oder mehr als einen Wert für die Datei benötigen, gehen Sie wie folgt vor:

{ 
   "/index.html" : { "size": 5467, "mime_type" : "foo" },
   "/about.html" : { "size": 3425, "mime_type" : "foo" }
   "/css/main.css" : { "size": 9876, "mime_type" : "bar" }
}
user949300
quelle
0

In Python ist das Wörterbuch ein veränderbares Objekt. Auf der anderen Seite ist Tupel ein unveränderliches Objekt.

Wenn Sie den Wörterbuchschlüssel ändern müssen, müssen Sie das Wertepaar häufig oder jedes Mal ändern. Ich schlage vor, Wörterbuch zu verwenden.

Wenn Sie feste / statische Daten haben, empfehle ich Tupel zu verwenden.

# dictionary define.
a = {}
a['test'] = 'first value'

# tuple define.
b = ()
b = b+(1,)

# here, we can change dictionary value for key 'test'
a['test'] = 'second'

Tupeldaten können jedoch nicht mit dem Zuweisungsoperator geändert werden.

Patel vertiefen
quelle