Python-Programmierung: Listen, Dictionaries, Mengen
Aus Wikibooks
Zahlen, Zeichenketten, Wahrheitswerte, selbst Pythons komplexe Zahlen sind einfache Datentypen. Sie repräsentieren genau einen Wert. Die komplexen Abläufe in der realen Welt, die wir mit Programme abbilden wollen, zeigt sich aber weitaus komplexer. Oft arbeiten wir mit einer Vielzahl von Daten gleichzeitig und sei es nur, der Einkaufzettel mit dem wir durch den Supermarkt schlendern, um unseren Einkaufswagen zu füllen.
Bleiben wir einen Moment beim diesem Beispiel und betrachten dieses Drahtgitterungetüm, dass wir erst mühsam mit einer Euromünze abketten müssen, einmal aus dem Blickwinkel der Informatik bzw, der Mathematik. So ein Einkaufswagen ist eine Art Container der Objekte, von Milchtüten über 500g Hackfleischpackungen, aufnimmt. Wir können Elemente hineintun, entnehmen und, durch hineinschauen überprüfen, ob wir bereits eine Packung Toastbrot hineingelegt haben oder nicht. Eine Ordnung gibt es im Einkaufswagen eigentlich nicht, jedenfalls nicht in meinem.
Ganz anders die Einkaufsliste, die fein säuberlich zeilenweise alles aufführt, was einzukaufen ist. Es gibt Leute, die sortieren ihre Liste sogar alphabetisch, manche sogar topologisch, nach den Gängen des Supermarktes.
Beides, der Einkaufswagen wie auch der Einkaufszettel, lassen sich als Containerklassenobjekte betrachten. Der Einkaufswagen selbst ist ein Ding, ein Objekt, dass man anfassen und durch den Supermarkt schubsen kann. Die besondere Eigenschaft von Containerobjekten, ist, andere Objekte in sich aufnehmen zu können, etwa Milchtüten.
Zurück zu Python: Python verfügt über drei eingebaute Containerklassen:
- Listen - Synonym werden auch die Begriffe Vektoren oder Arrays verwendet.
- Wörterbücher, auch Dictonaries oder präziser assoziative Arrays genannt.
- Mengen
Inhaltsverzeichnis |
[Bearbeiten] Listen
Listen, Sequenzen, Vektoren, Arrays, Felder bezeichnet eine geordnete Datenstruktur. Jedem Element der Liste ist ein Index zugeordnet, über den es adressiert werden kann. Wie in der Informatik üblich, beginnt die Zählung bei Null (0).
Python kennt zwei verschiedene Listenarten: veränderliche (mutable) und unveränderliche (immutable). Zu den unveränderlichen Listen zählten auch die Zeichenketten.
Wenden wir uns als erstes den unveränderlichen (immutable) Listen zu - den Tupeln.
[Bearbeiten] Tupel
Ein Tuple ist eine Liste beliebiger Objekte. Ein Tuple wird erzeugt, in dem die einzelnen Werte durch Kommata voneinander getrennt, hintereinander aufgeführt werden:
>>> t = (1, 2) >>> t (1, 2) >>> 1, 2, 3 (1, 2, 3)
Um die Lesbarkeit zu erhöhen, sollten Tuple immer mit runden Klammern erzeugt werden. Dabei ist ein Spezialfall zu beachten: Um ein Tupel mit nur einem Eintrag zu erhalten, wird ein abschließendes Komma verwendet.
>>> 1, (1,)
Die Inhalten eines Tuples müssen nicht notwendiger Weise Zahlen sein, ganz im Gegenteil sind alle Pythonobjekte als Element erlaubt und dass sogar munter durcheinander. Selbstverständlich lassen sich auf Tupel als Element in Tupeln verwenden. Es gibt eigentlich keine Beschränkung darin, was man in seinen Tupel stecken kann.
>>> meinTupel = ( 1, 2, 3, "Ein String", ( "rot", "grün", "blau"), None, True) (1, 2, 3, 'Ein String', ('rot', 'grün', 'blau'), None, True)
Selbstverständlich verfügen Objekte der Tupelklasse auch über eine Reihe von Methoden und Funktionen:
>>> len(meinTupel) # Anzahl der Elemente des Tupels 7 >>> None in meinTupel # Befindet sich der Wert None im Tupel? True >>> 5 in meinTupel # Oder die Zahl fünf? False >>> meinTupel * 3 # Drei flache Kopien (shallow copies) (1, 2, 3, 'Ein String', ('rot', 'grün', 'blau'), None, True, 1, 2, 3, 'Ein String', ('rot', 'grün', 'blau'), None, True, 1, 2, 3, 'Ein String', ('rot', 'grün', 'blau'), None, True) >>> meinTupel + ( "Ene", "mene", "Muh" ) # Konkatenation (1, 2, 3, 'Ein String', ('rot', 'grün', 'blau'), None, True, 'Ene', 'mene', 'Muh') >>> min(1, 4, 7, 4711, 42, 74, 12) # Kleinster Wert 1 >>> max(1, 4, 7, 4711, 42, 74, 12) # Größter Wert 4711
Tupel, wie alle Listen, sind geordnete Strukturen, d.h. die Elemente behalten die Reihenfolge bei, mit der das Tupel erzeugt wurde. Auf einzelne Werte lässt sich über den Index zugreifen. Das erste Element hat den Index Null (0). Negative Indices drehen die Zählrichtung um, d.h. beginnen am Ende und zählen rückwärts:
>>> meinTupel[0] # Das 1. Element 1 >>> meinTupel[-1] # Das letzte Element True >>> meinTupel[0:3] # Die ersten drei Elemente (1, 2, 3) >>> meinTupel[1:-1] # Alle Elemente vom 2. bis zum vorletzten (2, 3, 'Ein String', ('rot', 'grün', 'blau'), None) >>> meinTupel[:3] # Die Null lässt sich auch weglassen (1, 2, 3) >>> meinTupel[3:] # Alle Elemente ab dem 4. ('Ein String', ('rot', 'grün', 'blau'), None, True) >>> meinTupel[:-1] # Alle Elemente bis auf das letzte Element (1, 2, 3, 'Ein String', ('rot', 'grün', 'blau'), None) >>> meinTupel[::2] # Jedes 2. Element (1, 3, ('rot', 'grün', 'blau'), True) >>> meinTupel[4][1] # Element 5 ist selbst ein Tupel, davon das 2. Element 'grün'
Die letzten Beispiele zeigen einen Teil der Leistungsfähigkeit des splicing-Operators ([::]), mit dem sehr elegant auf Teile einer Liste zugegriffen werden kann. Der Verwendung ist sehr einfach und folgt dem Schema [Anfang:Ende:Schrittweite].
Eine sehr praktische und oft genutzte Funktionalität ist die Möglichkeit über die Werte eines Tupels zu iterieren:
>>> meinTupel[1:-1] (2, 3, 'Ein String', ('rot', 'grün', 'blau'), None) >>> for item in meinTupel: ... print item ... 1 2 3 Ein String ('rot', 'grün', 'blau') None True
Manchmal wünscht man sich, zusätzlich auch noch den Index bei der Iteration zu verfügen. Hier kommt die eingebaute Funktion enumerate zur Hilfe, die Sequenzen aller Art als Argument annimmt:
>>> for index, item in enumerate(meinTupel): ... print "Index =", index, " -> ", item ... Index = 0 -> 1 Index = 1 -> 2 Index = 2 -> 3 Index = 3 -> Ein String Index = 4 -> ('rot', 'grün', 'blau') Index = 5 -> None Index = 6 -> True
Tupel sind ein nicht veränderbarer Datentyp (immutable), d.h. es können nicht nachträglich einzelne Werte verändert werden.
>>> meinTupel[0] = "Geht Nicht" Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: object doesn't support item assignment
[Bearbeiten] Warum unveränderliche Listen?
Die Frage drängt sich geradezu zwangsläufig auf: Wozu gibt es einen Datentyp, dessen Elemente sich nicht ändern lassen?
Eine Antwort lautet Effizienz. Tupel sind schnell und zeichnen sich durch einen, gegenüber den veränderlichen Listen, geringeren Speicherverbrauch aus, da der gesamte Overhead zur Verwaltung einer veränderlichen Datenstruktur wegfällt.
Desweiteren sollte man Tupel eher als Behälter für mehrere unterschiedliche Typen von Elementen ansehen, die (als Tupel) als Ganzes behandelt werden oder eine ganz bestimmte Semantik erfüllen, während Listen eher gleichartige Elemente beinhalten.
[Bearbeiten] Veränderbare Listen (mutable sequence types)
Alle Operationen, Methoden und Funktionen, die mit tupels möglich sind, lassen sich auch auf die mutable sequences anwenden, mit einer kleinen aber wichtigen Erweiterung: mutables sequences, die ich der Einfachheit halber Listen nenne, lassen sich ändern.
Während Tupelobjekte durch runde Klammern erzeugt werden, werden für anonyme Listenobjekte die eckigen Klammern verwendet:
>>> l = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] # Eine mutable list sequence >>> len(l) # Mit wie vielen Elementen? 10 >>> min(l) # Dem kleinsten Element? 1 >>> max(l) # Dem größten Element 10 >>> l[0] # Element 0 1 >>> l[-1] # Das letzte Element 10 >>> l[::2] # Die ungraden Elemente [1, 3, 5, 7, 9] >>> l[1::2] # Die gerade Elemente [2, 4, 6, 8, 10] >>> l[0] = -1 # Das erste Element ändern >>> l [-1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Der entscheidende Unterschied zum Tupel findet sich in der letzten Zuweisung des Beispielcodes. Listen lassen sich in place ändern. Wie bei Tupeln, bestehen auf für Listen keine Einschränkungen hinsichtlich der Typen der Elemente. Jeder Objekttype ist erlaubt, was Liste, Tupel, Wörterbücher, ja sogar Klassen und Funktionen mit einschließt:
>>> def eineFunktion(): ... print "Ich bin eine Funktion" ... >>> eineListe = [ None, None, -1, 2+3j, "Zeichenkette", ( "Tupel", "Mupel", "Dupel" ), [ ], 2, 3, 5, 7, 11, 13, eineFunktion ] >>> eineListe [None, None, -1, (2+3j), 'Zeichenkette', ('Tupel', 'Mupel', 'Dupel'), [], 2, 3, 5, 7, 11, 13, <function eineFunktion at 0x402f43e4>]
eineListe enthält einen richtigen Elementzoo mit den unterschiedlichsten Typen. [] repräsentiert die leere Liste, also eine Liste, ohne Elemente. Eine leere Liste oder Tuple werden in boolschen Ausdrücken als False bewertet. Natürlich kann man über Listen auch iterieren:
>>> for element in eineListe: ... if element: ... print element, " is True" ... else: ... print element, " is False" ... None is False None is False -1 is True (2+3j) is True Zeichenkette is True ('Tupel', 'Mupel', 'Dupel') is True [] is False 2 is True 3 is True 5 is True 7 is True 11 is True 13 is True <function eineFunktion at 0x402f43e4> is True
Natürlich lassen sich Elemente nicht nur ändern, sondern auch hinzufügen und löschen.
>>> del eineListe[0] # del löscht Elemente >>> eineListe [None, -1, (2+3j), 'Zeichenkette', ('Tupel', 'Mupel', 'Dupel'), [], 2, 3, 5, 7, 11, 13, <function eineFunktion at 0x402f43e4>] >>> eineListe.append("A") # Append Elemente hängt an die Liste an >>> eineListe.append("B") >>> eineListe.append("C") >>>> eineListe.insert(0,"a") # Insert fügt sie vor dem angegebenen Index ein. >>> eineListe.insert(0,"b") >>> eineListe.insert(0,"c") >>> eineListe ['c', 'b', 'a', None, -1, (2+3j), 'Zeichenkette', ('Tupel', 'Mupel', 'Dupel'), [], 2, 3, 5, 7, 11, 13, <function eineFunktion at 0x402f43e4>, 'A', 'B', 'C'] >>> eineListe.pop() # Pop entimmt das letzte Element und verkürzt die Liste 'C' >>> eineListe.pop() 'B' >>> eineListe.pop() 'A' ['c', 'b', 'a', None, -1, (2+3j), 'Zeichenkette', ('Tupel', 'Mupel', 'Dupel'), [], 2, 3, 5, 7, 11, 13, <function eineFunktion at 0x402f43e4>] >>> nochNeListe = [ "Lirum", "Larum", "Löffelstil" ] >>> eineListe.extend(nochNeListe) # Liste um eine Liste erweitern >>> eineListe ['c', 'b', 'a', None, -1, (2+3j), 'Zeichenkette', ('Tupel', 'Mupel', 'Dupel'), [], 2, 3, 5, 7, 11, 13, <function eineFunktion at 0x402f43e4>, 'Lirum', 'Larum', 'Löffelstil']
Mit Listen lassen sich eine ganze Reihe anderer Datentypen simulieren. Ein Stackspeicher (Kellerspeicher, LIFO) erhält man mit den beiden Listenmethoden append(Element) und pop(), eine Warteschlange (Queue, FIFO) in dem man statt append(Element) insert(0, Element) verwendet.
[Bearbeiten] Assoziative Listen (Dictionaries)
Der Name klingt abschrenckend technisch, die Idee der assoziativen Listen (Arrays) ist aber ebenso einfach, wie bestechend. Das gute alte Telefonbuch ist eine assoziative Liste, es bildet Namen auf Telefonnummern ab oder, technisch ausgedrückt, einen Schlüssel auf einen Wert. Python dictionaries (Wörterbücher) sind ähnlich, sie ordnen (assoziieren) einen Schlüssel einem Wert zu. Eine assoziative Liste, kann man sich am bestens als eine zweispaltige Tabelle vorstellen, in der links das steht, wonach man suchen möchte, der Schlüssel (key) und rechts, der Wert (value) dem dieser Schlüssel zugeordnet ist. Im Telefonbuch, sind die Schlüssel, die Namen, die Werte die Telefonnummern.
Zwischen Telefonbuch und Python dicts gibt es aber ein paar Unterschiede:
- Schlüssel müssen eindeutig sein. Während es im Telefonbuch hunderte Müllers, Meiers und Schmidts gibt, kann es in Python Wörterbüchern jeweils immer nur einen geben.
- Telefonbücher sind sortiert (nach DIN 5007-2). Python dicts besitzen keine Ordnung. Wie Listen, lässt sich über ein dict iterieren, die Reihenfolge ist aber mehr oder weniger zufällig und spiegelt die interne Implementierung wieder, die sich von Pythonversion zu Pythonversion (CPython, Jython, IronPython) unterscheiden kann. Mehr noch, kann sich die Reihenfolge, durch löschen oder hinzufügen von Werten ändern.
Die Effizienz der assoziativen Listen ist extrem gut. Der Aufwand beträgt O(n) = 1, d.h. er ist konstant. Egal wie viele ein Pythonwörterbuch enthält, ob 1, 10, 100 oder 1.000.000 Einträge, die Suche ist immer gleich schnell. Sie ist so schnell, dass Python selbst für seine interne Verwaltung, z.B. die Namespaces, exzessiven Gebrauch macht. Diese Geschwindigkeit hat allerdings ihren Preis. Während als Wert (value) eines dicts alle Python Typen erlaubt sind, sind die zulässigen Typen für die Schlüssel (key) beschränkt. Schlüssel müssen hashable sein. Hashbare Objekte verfügen über einen eindeutigen Hashwert, der sich während ihrer gesamten Lebensdauer nicht ändert. Dieser Wert lässt sich mit der eingebauten Funktion id() abfragen. Die veränderbaren Objektetypen, wie lists, dicts und Objekte, die über ihren Wert und nicht über ihre Objektidentität verglichen werden, sind nicht hashable und damit als Schlüsselwert ungeeignet.
>>> tageImMonat = { "Januar":31, "Februar":28, "März":31, "April":30, "Mai":31, "Juni":30, "Juli":31, "August":31, "September":30, "Oktober":31, "November":30, "Dezember":31} >>> tageImMonat["Mai"] # Abfrage 31 >>> tageImMonat["May"] # Nicht vorhandene Schlüssel lösen eine Exception aus. Traceback (most recent call last): File "<stdin>", line 1, in ? KeyError: 'May' >>> tageImMonat.get("May", -1) # Die get-Methode liefert einen Defaultwert, statt eine Exception zu werfen -1 >>> "May" in tageImMonat # Test auf enthalten sein False >>> "Mai" in tageImMonat True >>> tageImMonat.has_key("Mai") # Wie 'in' nur als Methode True >>> len(tageImMonat) # Anzahl der Wertpaare im dict 12
[Bearbeiten] Konstruktion von Wörterbüchern
Der Codeschnipsel zeigt, wie ein dict erzeugt werden kann. Konstruiert werden dicts mit den geschweiften Klammern ({}) oder mit der eingebauten Funktion dict(). Die Werte werden immer paarweise angegeben: erst der Schlüssel, dann der Wert. dict() ermöglicht verschiedene Konstruktionsvarianten:
>>> einDict = { "rot":"#ff0000", "blau":"#0000ff", "gruen":"#00ff00" } # Mit geschweiften Klammern >>> einDict {'blau': '#0000ff', 'gruen': '#00ff00', 'rot': '#ff0000'} >>> dict(rot="#ff0000", gruen="#00ff00", blau="#0000ff") # Mit den Schlüssen als Argumentnamen {'blau': '#0000ff', 'gruen': '#00ff00', 'rot': '#ff0000'} >>> dict({ "rot":"#ff0000", "blau":"#0000ff", "gruen":"#00ff00" }) # Mit geschweiften Kammern {'gruen': '#00ff00', 'blau': '#0000ff', 'rot': '#ff0000'} TypeError: dict expected at most 1 arguments, got 3 >>> dict([["rot", "#ff0000"], ["gruen", "#00ff00"], ["blau", "#0000ff"]]) # Als Liste von Schlüssel/Wertpaaren {'gruen': '#00ff00', 'blau': '#0000ff', 'rot': '#ff0000'} >>> zip(("rot", "gruen", "blau"),("#ff0000", "#00ff00", "#0000ff")) # zip paart Werte [('rot', '#ff0000'), ('gruen', '#00ff00'), ('blau', '#0000ff')] >>> dict(zip(("rot", "gruen", "blau"),("#ff0000", "#00ff00", "#0000ff"))) {'gruen': '#00ff00', 'blau': '#0000ff', 'rot': '#ff0000'}
Die oft wenig beachtete eingebaute Funktion zip() nimmt Listen gleicher Länge an und vereinigt zu eine Liste von Paaren. Bei zwei Listen als Argument, die erste mit den Schlüsseln, die zweite mit den Werten, entsteht eine Liste, die direkt an dict übergeben werden kann.
Wir im ersten Beispiel gezeigt, gibt es zwei unterschiedliche Varianten, Werte aus einem Pythonwörterbuch wieder heraus zu bekommen: Einerseits, in dem der Schlüssel wir ein Listenindex verwendet wird (myDict[myKey]), andererseits mit Hilfe der Dict-Objektmethode get(), z.B. myDict.get(myKey). Der entscheidende Unterschied zeigt sich beim Verhalten auf nicht existente Schlüssel im dict zuzugreifen:
>>> {}.get("Wusel") >>> {}["Wusel"] Traceback (most recent call last): File "<stdin>", line 1, in ? KeyError: 'Wusel'
[Bearbeiten] get() als switch/case Ersatz
Die get-Methode liefert in diesem Fall nichts, also ein None, zurück. Während der Zugriff über die eckigen Klammern eine Ausnahme der Klasse KeyError wirft. Statt ein None zu liefern, besteht bei get() auch die Möglichkeit, einen Defaultwert zu liefern. Mit diesem Mechanismus, lässt sich ein eleganter Auswahlschalter, ähnlich dem switch/case-Statements anderer Programmiersprachen realisieren:
>>> def FunktionA(): ... print "Ich bin Funktion A" ... >>> def FunktionB(): ... print "Ich bin Funktion B" ... >>> def FunktionC(): ... print "Ich bin Funktion C" ... >>> def FehlerFunktion(): ... print "Was ist los?" ... >>> def CaseFunktion(auswahl): ... { "A":FunktionA, ... "B":FunktionB, ... "C":FunktionC}.get(auswahl, FehlerFunktion)() ... >>> CaseFunktion("A") Ich bin Funktion A >>> CaseFunktion("B") Ich bin Funktion B >>> CaseFunktion("C") Ich bin Funktion C >>> CaseFunktion("X") Was ist los?
Dieses Beispiel demonstriert Pythons Eigenschaft, jeden Objekttyp als Wert in einem dict aufnehmen zu können, in diesem Fall Funktionsobjekte. Das Wörterbuch wird mit drei Schlüssel-/Wertpaaren initialisiert, mit den Auswahlnamen (A, B und C) als Schlüssel und den Funktionen, genaugenommen den Funktionsreferenzen, als Wert. Die get-Methode erhält als zweites Argument den Defaultwert, eine Referenz auf die Funktion, die im Fall eines unbekannten Namens aufgerufen werden soll. Bleibt noch die Frage zu klären, welche Aufgabe die runden Klammern hinter dem get()-Aufruf haben. Es besteht ein Unterschied zwischen einer Funktion und dem Aufruf einer Funktion. Im assoziativen Array haben wir nur die Funktionen, dass heißt die Referenzen auf die Funktionsobjekte, gespeichert. Was liefert get, riefe man CaseFunktion mit einem "A" auf? Ganz klar: FunktionA. Für sich genommen ist FunktionA aber nur eine Funktionsobjektreferenz aber noch nicht der Aufruf der Funktion. Diesen bewerkstelligen die angefügten runden Klammern, so, als hätte man FunktionA() geschrieben.
[Bearbeiten] Weitere dict-Methoden
Außer get und den eckigen Klammern gibt es noch weitere Methoden, mit denen man Wörterbücher manipulieren kann:
>>> myDict = { "Kuchen":"Schoko", 4711:"Omis Duft", None:"Ein klares Nein!" } >>> myDict {None: 'Ein klares Nein!', 'Kuchen': 'Schoko', 4711: 'Omis Duft'} >>> myDict.keys() # Liefert eine Liste aller Schlüssel [None, 'Kuchen', 4711] >>> myDict.values() # Die Liste aller Werte ['Ein klares Nein!', 'Schoko', 'Omis Duft'] >>> myDict.items() # Liefert eine Liste von Schlüssel/Wert-Pärchen [(None, 'Ein klares Nein!'), ('Kuchen', 'Schoko'), (4711, 'Omis Duft')] >>> for key, value in myDict.items(): # Über die man herrlich iterieren kann ... print key, "->", value ... None -> Ein klares Nein! Kuchen -> Schoko 4711 -> Omis Duft
dict-Keys müssen nicht immer Zeichenketten sein. Es ist völlig legitim, andere Werte zu verwenden, solange sie hashable sind. Es mag überraschen, aber None ist ein völlig legaler Schlüssel, so wie diese Werte auch:
>>> myDict[True] = "Wahr" # True als Key >>> myDict[False] = "Falsch" # False als Key >>> myDict[(0+1j)] = "Die komplexe Zahl 1i" # Eine komplexe Zahl als Key >>> def EineFunktion(): ... print "Hallo Welt" ... >>> myDict[EineFunktion] = "Die Funktion mit dem Namen 'Eine Funktion'" # Eine Funktion als Key >>> myDict[>>> for key, value in myDict.items(): ... print key, "->", value ... False -> Falsch True -> Wahr 1j -> Die komplexe Zahl 1i <function EineFunktion at 0x402f43e4> -> Die Funktion mit dem Namen 'Eine Funktion' Kuchen -> Schoko 4711 -> Omis Duft None -> Ein klares Nein!
Wie man auch in diesem Beispiel sehr gut sehen kann, ist die Reihenfolge, in der items() die Schlüsse-/Wertpaare des Wörterbuchs liefert, eher zufällig. Sie kann sich sogar zwischen Aufrufen ändern, sollte zwischenzeitlich das dict verändert worden sein. Es ist ein Fehler, sich auf irgend eine Reihenfolge zu verlassen. Gleiches gilt auch für keys(), values(), iterkeys(), itervalues() und iteritems().
Und noch ein paar, zum Teil sehr praktische dict-Methoden:
>>> myDict.clear() # Entleert das Wörterbuch >>> myDict {} >>> myDict["rot"] = "#ff0000" >>> myDict["gruen"] = "#00ff00" >>> myDict["blau"] = "#0000ff" >>> myDict {'gruen': '#00ff00', 'blau': '#0000ff', 'rot': '#ff0000'} >>> myDict.setdefault("rot", "#000000") '#ff0000' >>> myDict.setdefault("lila", "#000000") '#000000' >>> myDict {'gruen': '#00ff00', 'blau': '#0000ff', 'lila': '#000000', 'rot': '#ff0000'}
setdefault ist eine ungemein praktische Methode. Sie verhält sich wie get, sie sucht nach dem als erstes Argument angegeben Schlüssel und liefert, wenn vorhanden, den dazugehörigen Wert. Existiert der Schlüssel hingegen nicht, liefert setdefault den als zweites Argument angegeben Defaultwert und trägt diesen zusätzlich auch noch unter dem Schlüssel in das Wörterbuch ein.
[Bearbeiten] Mengen (Sets)
Mengen in Python sind ungeordnete Sammlungen von eindeutigen, hashbaren Objekten. Ungeordnet heißt, dass, dass die Elemente über keine Position innerhalb der Menge verfügen. Konsequenter Weise sind Indexierung, slicing und andere Operationen der Sequenztypen nicht möglich. Die Elemente eines Sets sind eindeutig, dass heißt, ein Element kann nur genau ein Mal in einer Menge enthalten sein, womit sich dieser Datentyp optimal zum beseitigen von Duplikaten eignet.
Python kennt zwei Mengentypen: <doe>set und frozenset. Die sich analog zu mutable lists und tupel verhalten. frozensets/s sind unveränderbar, d.h. eine einmal erzeugte Menge kann nicht mehr verändert werden. Es lassen sich keine Elemente hinzufügen oder entfernen. frozensets sind hashable und können in assoziativen Arrays (dict) oder Mengen verwendet werden. sets sind veränderbar, d.h. erlauben das Hinzufügen und Löschen von Elemente, sind aber nicht hashable und können daher auch nicht in dicts oder Mengen verwendet werden.
Es gibt keine Kurznotation, wie die runden Klammern für Tupel, mit dem sich Mengen erzeugen lassen, sondern nur die beiden Konstruktoren set() und frozenset()
Eine leere Menge besitzt den Wahrheitswert False.
>>> eineMenge = set(("A", "B", "C")) # Konstruktion eines mutbale sets >>> eineMenge set(['A', 'C', 'B']) >>> eineAndereMenge = set(("A", "X", "X", "Y", "Z", "B", "C")) >>> eineAndereMenge # Duplikate werden entfernt set(['A', 'C', 'B', 'Y', 'X', 'Z'])
[Bearbeiten] Rechnen mit Mengen
Für Mengen stehen die üblichen mathematischen Operationen, wie Vereinigung, bilden der Schnittmenge, Differenzmenge und der symmetrischen Differenzmenge:
>>> eineWeitereMenge = set((1, 2, 3, "D", "E", "F")) >>> eineMenge | eineAndereMenge | eineWeitereMenge # Die Vereinungsmenge set(['A', 1, 'C', 'B', 'E', 'D', 'F', 2, 3, 'Y', 'X', 'Z']) >>> eineMenge.union(eineAndereMenge) # Vereinigung mit Methodenfunktion set(['A', 'C', 'B', 'Y', 'X', 'Z']) >>> eineMenge & eineAndereMenge # Die Schnittmenge set(['A', 'C', 'B']) >>> eineAndereMenge.intersection(eineWeitereMenge) # Mit der Schnittmengenmethode set([]) >>> eineAndereMenge - eineMenge # Diffenzmenge: Alle Elemente von A, die nicht in B sind set(['Y', 'X', 'Z']) >>> eineAndereMenge.difference(eineWeitereMenge) set(['A', 'C', 'B', 'Y', 'X', 'Z']) >>> eineAndereMenge ^ eineWeitereMenge # Symetrische Differenz: Nur in A oder in B aber nicht in beiden. set(['A', 1, 2, 3, 'E', 'D', 'F', 'C', 'B', 'Y', 'X', 'Z']) >>> eineMenge.symmetric_difference(eineAndereMenge) set(['Y', 'X', 'Z'])
[Bearbeiten] Prädikate - Aussagen über Mengen
Mengen lassen sich Vergleichen - Untereinander oder gegen einzelne Elemente:
>>> 1 in eineMenge False >>> 1 not in eineAndereMenge True >>> 1 in eineWeitereMenge True >>> eineMenge.isdisjoint(eineAndereMenge) # Wahr, wenn die Schnittmenge leer ist. Erst ab Python 2.6 False >>> eineMenge.issubset(eineAndereMenge) # A ist in B enthalten - Teilmenge True >>> eineMenge < eineAndereMenge # Echte Teilmenge: A ist Teilmenge von B, aber A != B True >>> eineMenge <= eineMenge # Ist Teilmenge True >>> eineMenge < eineMenge # Aber keine echte Teilmenge False >>> len(eineWeitereMenge) # Mächtigkeit, dass heißt Anzahl der Elemente in der Menge 6
[Bearbeiten] Manipulationen von Mengen des Typs set
Die bisherigen Funktionen und Methoden waren gleichermaßen auf set und frozenset anwendbar. Die nachfolgenden verändern die Menge und sind daher nur mit set möglich.
>>> eineMenge |= eineAndereMenge # Vereinungs in eineMenge hinein >>> eineMenge set(['A', 'C', 'B', 'Y', 'X', 'Z']) >>> BZ = set(("B", "Z", 77, 88, 99)) >>> BZ &= eineMenge # Schnittmenge >>> BZ set(['Z', 'B']) >>> eineMenge.add(1) # Elemente hinzufügen >>> eineMenge.add(2) >>> eineMenge.add(3) >>> eineMenge set(['A', 1, 'C', 'B', 2, 3, 'Y', 'X', 'Z']) >>> eineMenge.remove("Z") # Entfernt eine Element... >>> eineMenge.remove("Z") # ...und wirft eine Exception, wenn es nicht existiert Traceback (most recent call last): File "<stdin>", line 1, in ? KeyError: 'Z' >>> eineMenge.discard('C') # Wie remove... >>> eineMenge.discard('C') # ... ignoriert aber den Fall, dass das zu löschende Objekt nicht existiert >>> eineMenge.pop() # Entnimmt eine beliebiges Objekt 'A' >>> eineMenge set([1, 'B', 2, 3, 'Y', 'X']) >>> eineMenge.clear() # Leert die Menge >>> eineMenge set([])