Der Autor hat den COVID-19 Relief Fund dazu ausgewählt, eine Spende im Rahmen des Programms Write for DOnations zu erhalten.
Python 3 verfügt über eine Reihe von integrierten Datenstrukturen, einschließlich Tupel, Wörterbücher und Listen. Datenstrukturen bieten uns eine Möglichkeit, Daten zu organisieren und zu speichern. Das collections
-Modul hilft uns, Datenstrukturen effizient zu füllen und zu manipulieren.
In diesem Tutorial gehen wir drei Klassen im collections
-Modul durch, um Ihnen die Arbeit mit Tupeln, Wörterbüchern und Listen zu erleichtern. Wir verwenden namedtuples
, um Tupel mit benannten Feldern zu erstellen, defaultdict
, um Informationen in Wörterbüchern übersichtlich zu gruppieren, und deque
, um Elemente effizient zu beiden Seiten eines listenartigen Objekts hinzuzufügen.
In diesem Turorial arbeiten wir in erster Linie mit einem Bestand von Fischen, den wir modifizieren müssen, wenn Fische zu einem fiktiven Aquarium hinzugefügt oder aus diesem entfernt werden.
Um dieses Tutorial optimal zu nutzen, wird empfohlen, sich mit den Tupel-, Wörterbuch- und Listendatentypen vertraut zu machen; sowohl mit deren Syntax als auch mit der Art und Weise, Daten von ihnen abzurufen. Sie können für die notwendigen Hintergrundinformationen diese Tutorials durchsehen:
Python-Tupeln sind eine unwandelbare oder unveränderliche, geordnete Sequenz von Elementen. Tupel werden häufig für die Darstellung von Spaltendaten verwendet, beispielsweise für Zeilen aus einer CSV-Datei oder Reihen aus einer SQL-Datenbank. Ein Aquarium könnte seinen Bestand an Fischen als eine Reihe von Tupeln erfassen.
Ein individueller Fischtupel:
("Sammy", "shark", "tank-a")
Dieses Tupel besteht aus drei Zeichenfolgenelementen.
Das Tupel ist zwar in gewisser Weise nützlich, aber es gibt nicht klar an, wofür jedes seiner Felder steht. In Wirklichkeit ist Element 0
ein Name, Element 1
eine Spezies und Element 2
das Haltebecken.
Erläuterung der Fischtupelfelder:
Name | Spezies | Becken |
---|---|---|
Sammy | shark | tank-a |
Diese Tabelle verdeutlicht, dass jedes der drei Elemente des Tupels eine klare Bedeutung hat.
Mit namedtuple
aus dem collections
-Modul können Sie jedem Element eines Tupels explizite Namen hinzufügen, um diese Bedeutungen in Ihrem Python-Programm klarzustellen.
Wir verwenden namedtuple
zum Erstellen einer Klasse, die jedes Element des Fischtupels klar benennt:
from collections import namedtuple
Fish = namedtuple("Fish", ["name", "species", "tank"])
from collections import namedtuple
gibt Ihrem Python-Programm Zugriff auf die Factoryfunktion namedtuple
. Der Funktionsaufruf namedtuple()
gibt eine Klasse zurück, die an den Namen Fish
gebunden ist. Die Funktion namedtuple()
hat zwei Argumente: den gewünschten Namen unserer neuen Klasse "Fish"
und eine Liste mit benannten Elementen ["name", "species", "tank"]
.
Wir können die Fish
-Klasse verwenden, um das Fischtupel von vorhin zu repräsentieren:
sammy = Fish("Sammy", "shark", "tank-a")
print(sammy)
Wenn wir diesen Code ausführen, sehen wir die folgende Ausgabe:
OutputFish(name='Sammy', species='shark', tank='tank-a')
sammy
wird mit der Fish
-Klasse instanziiert. sammy
ist ein Tupel mit drei klar benannten Elementen.
Auf die Felder von sammy
kann über ihren Namen oder mit einem traditionellen Tupelindex zugegriffen werden:
print(sammy.species)
print(sammy[1])
Wenn wir diese beiden print
-Aufrufe ausführen, sehen wir die folgende Ausgabe:
Outputshark
shark
Der Zugriff auf .species
gibt denselben Wert zurück wie der Zugriff auf das zweite Element von sammy
mit [1]
.
Die Verwendung von namedtuple
aus dem collections
-Modul macht Ihr Programm lesbarer, wobei die wichtigen Eigenschaften eines Tupels (dass sie unveränderlich und geordnet sind) bewahrt bleiben.
Darüber hinaus fügt die Factoryfunktion namedtuple
mehrere zusätzliche Methoden zu Instanzen von Fish
hinzu.
Verwenden Sie ._asdict()
, um eine Instanz in ein Wörterbuch zu konvertieren:
print(sammy._asdict())
Wenn wir print
ausführen, sehen Sie eine Ausgabe wie die folgende:
Output{'name': 'Sammy', 'species': 'shark', 'tank': 'tank-a'}
Das Aufrufen von .asdict()
auf sammy
gibt ein Wörterbuch zurück, das jedem der drei Feldnamen ihre entsprechenden Werte zuordnet.
Python-Versionen, die älter als 3.8 sind, geben diese Zeile möglicherweise etwas anders aus. Sie könnten beispielsweise ein OrderedDict
anstelle des hier gezeigten, einfachen Wörterbuchs sehen.
Anmerkung: In Python werden Methoden mit vorangehenden Unterstrichen gewöhnlich als „privat“ eingestuft. Weitere Methoden, die von namedtuple
bereitgestellt werden (wie _asdict()
, ._make()
, ._replace()
, usw.), sind jedoch öffentlich.
Es ist oft nützlich, Daten in Python-Wörterbüchern zu sammeln. defaultdict
aus dem collections
-Modul kann uns helfen, Informationen schnell und übersichtlich in Wörterbüchern zusammenzustellen.
defaultdict
gibt nie einen KeyError
aus. Wenn kein Schlüssel vorhanden ist, fügt defaultdict
stattdessen einfach einen Platzhalterwert ein und gibt ihn zurück:
from collections import defaultdict
my_defaultdict = defaultdict(list)
print(my_defaultdict["missing"])
Wenn wir diesen Code ausführen, sehen wir eine Ausgabe wie die folgende:
Output[]
defaultdict
fügt einen Platzhalterwert ein und gibt ihn zurück, anstatt einen KeyError
auszugeben. In diesem Fall haben wir den Platzhalterwert als Liste angegeben.
Reguläre Wörterbücher hingegen geben bei fehlenden Schlüsseln einen KeyError
aus:
my_regular_dict = {}
my_regular_dict["missing"]
Wenn wir diesen Code ausführen, sehen wir eine Ausgabe wie die folgende:
OutputTraceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'missing'
Das reguläre Wörterbuch my_regular_dict
gibt einen KeyError
aus, wenn wir versuchen, auf einen Schlüssel zuzugreifen, der nicht vorhanden ist.
defaultdict
verhält sich anders als ein reguläres Wörterbuch. Statt einen KeyError
auf einen fehlenden Schlüssel auszugeben, ruft defaultdict
den Platzhalterwert ohne Argumente auf, um ein neues Objekt zu erstellen. In diesem Fall list()
, um eine leere Liste zu erstellen.
Um mit unserem fiktiven Aquarium-Beispiel fortzufahren, nehmen wir an, wir hätten eine Liste von Fischtupeln, die den Bestand eines Aquariums repräsentieren:
fish_inventory = [
("Sammy", "shark", "tank-a"),
("Jamie", "cuttlefish", "tank-b"),
("Mary", "squid", "tank-a"),
]
Es gibt drei Fische in dem Aquarium – Name, Spezies und Haltebecken sind in diesen drei Tupeln notiert.
Unser Ziel ist es, unseren Bestand nach Becken zu organisieren. Wir wollen die Liste der in jedem Becken vorhandenen Fische kennen. Anders ausgedrückt: Wir wollen ein Wörterbuch, das "tank-a"
["Jamie", "Mary"]
und "tank-b"
["Jamie"]
zuordnet.
Wir können defaultdict
verwenden, um den Fisch nach Becken zu gruppieren:
from collections import defaultdict
fish_inventory = [
("Sammy", "shark", "tank-a"),
("Jamie", "cuttlefish", "tank-b"),
("Mary", "squid", "tank-a"),
]
fish_names_by_tank = defaultdict(list)
for name, species, tank in fish_inventory:
fish_names_by_tank[tank].append(name)
print(fish_names_by_tank)
Nach Ausführung dieses Codes sehen wir die folgende Ausgabe:
Outputdefaultdict(<class 'list'>, {'tank-a': ['Sammy', 'Mary'], 'tank-b': ['Jamie']})
fish_names_by_tank
wird als ein defaultdict
deklariert, das standardmäßig list()
einfügt, anstatt einen KeyError
auszugeben. Da dies garantiert, dass jeder Schlüssel in fish_names_by_tank
auf eine list
verweist, können wir frei .append()
aufrufen, um Namen zu der Liste jedes Beckens hinzuzufügen.
defaultdict
hilft Ihnen hier, weil es die Wahrscheinlichkeit unerwarteter KeyErrors
reduziert. Die Reduzierung der unerwarteten KeyErrors
bedeutet, dass Ihr Programm klarer und mit weniger Zeilen geschrieben werden kann. Konkreter gesagt: Mit dem defaultdict
-Idiom können Sie manuelles Instanziieren einer leeren Liste für jedes Becken vermeiden.
Ohne defaultdict
hätte der for
-Schleifenkörper möglicherweise eher wie folgt ausgesehen:
...
fish_names_by_tank = {}
for name, species, tank in fish_inventory:
if tank not in fish_names_by_tank:
fish_names_by_tank[tank] = []
fish_names_by_tank[tank].append(name)
Die Verwendung eines regulären Wörterbuchs (statt eines defaultdict
) bedeutet, dass der for
-Schleifenkörper immer das Vorhandensein des gegebenen tank
in fish_names_by_tank
überprüfen muss. Erst nachdem wir überprüft haben, dass tank
bereits in fish_names_by_tank
vorhanden ist, oder gerade mit einem []
initialisiert wurde, können wir den Fischnamen ergänzen.
defaultdict
kann dazu beitragen, beim Füllen der Wörterbücher den Standardcode zu reduzieren, da es nie einen KeyError
ausgibt.
Python-Listen sind eine wandelbare oder veränderliche, geordnete Sequenz von Elementen. Python kann Listen in konstanter Zeit ergänzen (die Länge der Liste hat keine Auswirkungen auf die Zeit, die zum Ergänzen benötigt wird), aber das Einfügen am Anfang einer Liste kann langsamer sein – die Zeitdauer erhöht sich beim Anwachsen der Liste.
Im Sinne der Big-O-Notation ist das Ergänzen einer Liste ein O(1)
-Vorgang mit konstanter Zeit. Im Gegensatz ist das Einfügen am Anfang einer Liste langsamer mit einer O(n)
-Leistung.
Anmerkung: Softwareingenieure messen die Leistung von Vorgängen oft mit der sogenannten „Big O“-Notation. Wenn die Größe einer Eingabe keine Auswirkungen auf die Zeit hat, die zum Ausführen eines Vorgangs benötigt wird, spricht man von einem Ablauf in konstanter Zeit oder O(1)
(„Big O von 1“). Wie Sie oben gelernt haben, kann Python Listen mit konstanter Zeitleistung, auch als O(1)
bekannt, ergänzen.
Manchmal beeinflusst die Größe einer Eingabe direkt die Zeit, die zum Ausführen eines Vorgangs benötigt wird. Das Einfügen am Anfang einer Python-Liste zum Beispiel läuft umso langsamer ab, je mehr Elemente in der Liste vorhanden sind. Die Big-O-Notation verwendet den Buchstaben n
, um die Größe der Eingabe darzustellen. Das bedeutet, dass das Hinzufügen von Elementen am Anfang einer Python-Liste in „linearer Zeit“ oder O(n)
(„Big O von n“) abläuft.
Im Allgemeinen sind O(1)
-Vorgänge schneller als O(n)
-Vorgänge.
Wir können am Anfang einer Python-Liste einfügen:
favorite_fish_list = ["Sammy", "Jamie", "Mary"]
# O(n) performance
favorite_fish_list.insert(0, "Alice")
print(favorite_fish_list)
Wenn wir Folgendes ausführen, sehen wir eine Ausgabe wie die folgende:
Output['Alice', 'Sammy', 'Jamie', 'Mary']
Die .insert(index, object)
-Methode in der Liste ermöglicht uns, „Alice“
am Anfang von favorite_fish_list
einzufügen. Jedoch hat das Einfügen am Anfang einer Liste eine O(n)
-Leistung. Wenn die Länge der favorite_fish_list
wächst, wird die Zeit, um einen Fisch am Anfang der Liste einzufügen, proportional anwachsen und immer länger dauern.
deque
(ausgesprochen „Deck“) aus dem collections
-Modul ist ein listenähnliches Objekt, das es uns ermöglicht, Elemente am Anfang oder Ende einer Sequenz mit konstanter Zeit (O(1)
)-Leistung einzufügen.
Geben Sie ein Element am Anfang eines deque
ein:
from collections import deque
favorite_fish_deque = deque(["Sammy", "Jamie", "Mary"])
# O(1) performance
favorite_fish_deque.appendleft("Alice")
print(favorite_fish_deque)
Nach Ausführung dieses Codes sehen wir die folgende Ausgabe:
Outputdeque(['Alice', 'Sammy', 'Jamie', 'Mary'])
Wir können ein deque
anhand einer bereits vorhandenen Sammlung von Elementen instanziieren, in diesem Fall einer Liste mit drei bevorzugten Fischnamen. Das Aufrufen der appendleft
-Methode von favorite_fish_deque
ermöglicht uns, ein Element am Anfang unserer Sammlung mit O(1)
-Leistung einzufügen. O(1)
-Leistung bedeutet, dass die Zeit, die zum Hinzufügen eines Elements am Anfang von favorite_fish_deque
benötigt wird, nicht zunimmt, selbst wenn favorite_fish_deque
Tausende oder Millionen von Elementen enthält.
Anmerkung: Obwohl deque
Einträge am Anfang einer Sequenz effizienter als eine Liste hinzufügt, führt deque
nicht alle seine Vorgänge effizienter als eine Liste aus. Beispielsweise hat das Zugreifen auf ein zufälliges Element in einem deque
eine O(n)
-Leistung, das Zugreifen auf ein zufälliges Element in einer Liste jedoch eine O(1)
-Leistung Verwenden Sie deque
, wenn es wichtig ist, Elemente schnell zu beiden Seiten Ihrer Sammlung hinzuzufügen oder zu entfernen. Ein vollständiger Vergleich der Zeitleistung ist auf Pythons Wiki verfügbar.
Das collections
-Modul ist ein leistungsfähiger Teil der Python-Standardbibliothek, mit dem Sie übersichtlich und effizient Daten bearbeiten können. Dieses Tutorial behandelte drei der Klassen, die vom collections
-Modul bereitgestellt werden, einschließlich namedtuple
, defaultdict
und deque
.
Nun können Sie die Dokumentation des collection
-Moduls nutzen, um mehr über andere verfügbare Klassen und Dienstprogramme zu erfahren. Um im Allgemeinen mehr über Python zu erfahren, können Sie unsere Tutorialreihe Codieren in Python 3 lesen.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!