Unterabschnitte


5. Datenstrukturen

Dieses Kapitel beschreibt einige Dinge, die Sie zuvor bereits gelernt haben, mehr im Detail und behandelt auch einige neue.


5.1 Mehr über Listen

Der Datentyp Liste hat noch weitere Methoden. Dies sind alle Methoden von Listen-Objekten:

insert(i, x)
Füge ein Element an einer bestimmten Stelle ein. Das erste Argument ist der Index, vor dem eingefügt werden soll, so daß a.insert(0, x) zu Beginn einfügt und a.insert(len(a), x) äquivalent zu a.append(x) ist.

append(x)
Äquivalent zu a.insert(len(a), x).

index(x)
Gib den Index des ersten Elements in der Liste zurück, dessen Wert gleich x ist. Falls kein solcher existiert, so ist dies ein Fehler.

remove(x)
Entferne das erste Element der Liste, dessen Wert x ist. Falls kein solches existiert, so ist dies ein Fehler.

sort()
Sortiere die Elemente der Liste, in der Liste selbst.

reverse()
Invertiere die Reihenfolge der Listenelemente, in dieser selbst.

count(x)
Gib die Anzahl des Auftretens des Elements x in der Liste zurück.

Ein Beispiel, das alle Listen-Methoden verwendet:


>>> a = [66.6, 333, 333, 1, 1234.5]
>>> print a.count(333), a.count(66.6), a.count('x')
2 1 0
>>> a.insert(2, -1)
>>> a.append(333)
>>> a
[66.6, 333, -1, 333, 1, 1234.5, 333]
>>> a.index(333)
1
>>> a.remove(333)
>>> a
[66.6, -1, 333, 1, 1234.5, 333]
>>> a.reverse()
>>> a
[333, 1234.5, 1, 333, -1, 66.6]
>>> a.sort()
>>> a
[-1, 1, 66.6, 333, 333, 1234.5]


5.1.1 Werkzeuge zur funktionalen Programmierung

Es gibt drei eingebaute Funktionen, die alle sehr nützlich in Kombination mit Listen sind: filter(), map() und reduce().

"filter(function, sequence)" gibt eine Sequenz (wenn möglich, des selben Typs) zurück, die aus den Elementen der Sequenz besteht, für die function(item) wahr ist, z.B. um Primzahlen zu berechnen:


>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]

"map(function, sequence)" ruft function(item) für jedes Listenelement auf und gibt eine Liste der zurück gegebenen Werte zurück. Zum Beispiel könnte man Kubikzahlen wie folgt berechnen:


>>> def cube(x): return x*x*x
...
>>> map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

Man darf mehr als eine Sequenz übergeben; die Funktion muß dann genausoviele Argumente haben wie es Sequenzen gibt, und sie wird mit dem entsprechenden Element der jeweiligen Sequenz (oder None, falls eine Sequenz kürzer als die andere ist) aufgerufen. Falls None als Funktion übergeben wird, wird es mit einer Funktion ersetzt, die ihr(e) Argument(e) zurück gibt.

Kombiniert man diese zwei Spezialfälle, so sehen wir, daß "map(None, list1, list2)" eine bequeme Art ist, ein Paar von Listen in eine Liste von Paaren umzuwandeln, z.B.:


>>> seq = range(8)
>>> def square(x): return x*x
...
>>> map(None, seq, map(square, seq))
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49)]

"reduce(func, sequence)" gibt einen einzigen Wert zurück, der sich ergibt, wenn man die zwei-stellige Funktion func auf die ersten zwei Elemente der Sequenz, dann auf das Resultat und das nächste Element, etc. anwendet. Um etwa die Summe der Zahlen von 1 bis 10 zu berechnen:


>>> def add(x,y): return x+y
...
>>> reduce(add, range(1, 11))
55

Falls die Sequenz nur ein Element hat, wird dieses eine zurück gegeben. Falls sie leer ist, wird eine Ausnahme ausgelöst.

Ein drittes Argument kann übergeben werden, um einen Startwert anzugeben. In diesem Fall wird der Startwert bei einer leeren Sequenz zurück gegeben. Die Funktion wird dann auf den Startwert und das erste Element erstmalig angewendet, dann auf das Resultat und das nächste Element, u.s.w. Beispiel:


>>> def sum(seq):
...     def add(x,y): return x+y
...     return reduce(add, seq, 0)
...
>>> sum(range(1, 11))
55
>>> sum([])
0


5.2 Die del-Anweisung

Es gibt eine Möglichkeit, ein Element aus einer Liste zu entfernen, indem man seinen Index anstatt seinen Wert angibt: die del-Anweisung. Sie kann auch verwendet werden, um Teilbereiche aus einer Liste zu entfernen (was wir bereits mit der Zuweisung einer leeren Liste an den Bereich getan haben). Beispiel:


>>> a
[-1, 1, 66.6, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.6, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.6, 1234.5]

del kann auch verwendet werden, um Variablen gänzlich zu löschen:


>>> del a

Die anschließende Referenzierung (Verwendung) des Namens a ist ein Fehler (jedenfalls solange ihm kein anderer Wert zugewiesen wird). Wir werden später noch andere Möglichkeiten sehen, del zu verwenden.


5.3 Tupel und Sequenzen

Wir haben gesehen, daß Listen und Strings viele gemeinsame Eigenschaften haben, etwa Indizierungs- und Teilbereichs-Operatoren. Es sind zwei Beispiele für Sequenz-Datentypen. Da Python eine sich entwickelnde Sprache ist, könnten andere Sequenz-Typen noch hinzukommen. Es gibt noch einen anderen Standard-Sequenz-Typ: das Tupel.

Ein Tupel besteht aus einer Anzahl von Werten, die durch Kommata getrennt sind, z.B.:


>>> t = 12345, 54321, 'hello!'
>>> t[0]
12345
>>> t
(12345, 54321, 'hello!')
>>> # Tupel duerfen verschachtelt sein:
... u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))

Wie man sieht, werden ausgegebene Tupel immer in runde Klammern gesetzt, so daß verschachtelte Tupel korrekt interpretiert werden. Bei der Eingabe können sie mit oder ohne umgebende Klammern verwendet werden, obwohl die Klammern oft sowieso notwendig sind (wenn ein Tupel Teil eines größeren Ausdrucks ist).

Tupel haben viele Anwendungen, etwa als (x, y)-Koordinatenpaare, Mitarbeiter-Datensätze aus der Datenbank, etc. Genau wie Strings sind Tupel unveränderlich: man kann einzelnen Elementen von Tupeln nichts zuweisen (man kann jedoch einen Großteil dieses Effekts durch Teilbereichs-Bildung und Aneinanderfügung simulieren).

Ein besonderes Problem ist die Erzeugung von Tupeln mit 0 oder nur 1 Element: die Syntax bietet einige Tricks, um das zu ermöglichen. Leere Tupel werden durch ein leeres Klammernpaar erzeugt. Ein Tupel mit genau einem Element wird erzeugt, indem man diesem Element ein Komma nachstellt (ein einzelnes Element in Klammern genügt nicht). Häßlich - aber wirkungsvoll. Beispiel:


>>> empty = ()
>>> singleton = 'hello',    # <-- Beachte abschliessendes Komma!
>>> len(empty)
0
>>> len(singleton)
1
>>> singleton
('hello',)

Die Anweisung t = 12345, 54321, 'hello!' ist ein Beispiel für das sogenannte Tupel-Einpacken (engl. tuple packing): die Werte 12345, 54321 und 'hello!' werden in ein Tupel eingepackt. Die umgekehrte Operation ist auch möglich, z.B.:


>>> x, y, z = t

Dies nennt man, sinnigerweise, Tupel-Auspacken (engl. tuple unpacking). Das Auspacken von Tupeln verlangt, daß die Liste der Variablen auf der linken Seite die gleiche Anzahl von Elementen hat wie das Tupel selbst. Man beachte, daß Mehrfachzuweisungen lediglich eine Kombination von Ein- und Auspacken von Tupeln ist!

Gelegentlich ist die entsprechende Operation auf Listen nützlich: Listen-Auspacken. Sie wird unterstützt, indem die Variablenliste in eckige Klammern gesetzt wird:


>>> a = ['spam', 'eggs', 100, 1234]
>>> [a1, a2, a3, a4] = a


5.4 Dictionaries

Ein anderer nützlicher, in Python eingebauter Datentyp ist das sogenannte Dictionary (engl. für Wörterbuch, Verzeichnis). Dictionaries kann man manchmal in anderen Sprachen unter den Begriffen ,,assoziativer Speicher`` oder ,,assoziative Vektoren`` wiederfinden. Im Gegensatz zu Sequenzen, die mit einem Zahlen-Intervall indiziert werden, werden Dictionaries über Schlüssel indiziert, die irgendeinen unveränderlichen Typ haben können. Strings und Zahlen können immer solche Schlüssel sein. Tupel können als Schlüssel verwendet werden, wenn sie nur Strings, Zahlen oder Tupel enthalten. Listen können nicht als Schlüssel verwendet werden, da Listen mit der append()-Methode direkt verändert werden können.

Am besten stellt man sich Dictionaries als eine ungeordnete Menge von Schlüssel:Wert-Paaren vor, unter der Randbedingung, daß die Schlüssel eindeutig sein müssen (innerhalb eines Dictionaries). Ein Paar geschwungener Klammern erzeugt ein leeres Dictionary: {}. Eine durch Kommata getrennte Liste von Schlüssel:Wert-Paaren innerhalb der Klammern fügt die initialen Schlüssel:Wert-Paare in das Dictionary ein. So werden Dictionaries auch ausgegeben.

Die Hauptoperationen auf einem Dictionary sind das Speichern eines Wertes unter einem Schlüssel und das Abrufen dieses Wertes bei Angabe des Schlüssels. Es ist auch möglich, ein Schlüssel:Wert-Paar mit del zu löschen. Wird beim Speichern ein Schlüssel verwendet, der bereits existiert, so wird der alte damit assoziierte Schlüssel vergessen. Es ist ein Fehler, einen Wert mit einem nicht existierenden Schlüssel abzurufen.

Die keys()-Methode eines Dictionary-Objektes gibt eine Liste aller in dem Dictionary verwendeten Schlüssel zurück - in zufälliger Reihenfolge (brauchen Sie sie sortiert, dann wenden Sie einfach die sort()-Methode auf die Liste der Schlüssel an). Um zu testen, ob ein einzelner Schlüssel in einem Dictionary vorkommt, verwende man die has_key()-Methode eines Dictionaries.

Hier ist ein kleines Beispiel mit einem Dictionary:


>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>> tel['jack']
4098
>>> del tel['sape']
>>> tel['irv'] = 4127
>>> tel
{'guido': 4127, 'irv': 4127, 'jack': 4098}
>>> tel.keys()
['guido', 'irv', 'jack']
>>> tel.has_key('guido')
1


5.5 Mehr über Bedingungen

Die in while- und if-Anweisungen oben verwendeten Bedingungen können neben Vergleichen auch andere Operatoren beinhalten.

Die Vergleichsoperatoren in und not in prüfen, ob ein Wert in einer Sequenz vorkommt (oder nicht). Die Operatoren is und is not vergleichen, ob zwei Objekte wirklich das gleiche Objekt sind. Das ist nur für veränderliche Objekte wie Listen von Bedeutung. Alle Vergleichsoperatoren haben die gleiche Priorität, die kleiner ist als die aller numerischen Operatoren.

Vergleiche können verkettet werden. a < b == c z.B. prüft, ob a kleiner ist als b und außerdem, ob b gleich c ist.

Vergleiche können mit den Booleschen Operatoren and und or kombiniert werden, und das Resultat eines Vergleichs (oder irgendeines anderen Booleschen Ausdrucks) kann mit not negiert werden. All diese Operatoren haben wiederum niedrigere Priorität als Vergleichsoperatoren. Unter ihnen hat not die höchste Priorität und or die geringste, so daß A and not B or C äquivalent ist zu (A and (not B)) or C. Natürlich können Klammern gesetzt werden, um die gewünschte Zusammensetzung auszudrücken.

Die Booleschen Operatoren and und or sind sogenannte Abkürzungs-Operatoren (engl. shortcut): ihre Argumente werden von links nach rechts ausgewertet, und die Auswertung wird beendet, sobald das Ergebnis feststeht. Wenn etwa A und C wahr sind, aber B ist falsch, so wertet A and B and C den Ausdruck C nicht aus. Allgemein gilt, daß der Rückgabewert eines Abkürzungs-Operators (wenn als allgemeiner Wert und nicht als Boolescher Ausdruck verwendet) das zuletzt ausgewertete Argument ist.

Es ist möglich, das Resultat eines Vergleichs oder eines anderen Booleschen Ausdrucks einer Variablen zuzuweisen, z.B.


>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
>>> non_null = string1 or string2 or string3
>>> non_null
'Trondheim'

Man beachte daß in Python (anders als in C) Zuweisungen in Ausdrücken nicht erlaubt sind.


5.6 Vergleich von Sequenzen und anderen Typen

Sequenz-Objekte dürfen mit anderen Objekten vom gleichen Sequenz-Typ verglichen werden. Der Vergleich basiert auf lexikographischer Ordnung: zuerst werden die ersten beiden Elemente verglichen, und wenn sie sich unterscheiden, bestimmt dies bereits das Resultat. Wenn sie gleich sind, werden die nächsten beiden Elemente verglichen, und so weiter, bis eine der beiden Sequenzen erschöpft ist. Wenn zwei zu vergleichende Elemente selbst Sequenzen vom gleichen Typ sind, wird der lexikographische Vergleich rekursiv fortgesetzt. Falls alle Elemente einer Sequenz gleich sind, werden die Sequenzen als gleich betrachtet. Falls eine Sequenz eine Anfangssequenz der anderen ist, ist die gekürzte Sequenz die kleinere. Die lexikographische Ordnung für Strings verwendet die ASCII-Ordnung für einzelne Zeichen. Einige Beispiele für Vergleiche von Sequenzen des selben Typs:


(1, 2, 3)              < (1, 2, 4)
[1, 2, 3]              < [1, 2, 4]
'ABC' < 'C' < 'Pascal' < 'Python'
(1, 2, 3, 4)           < (1, 2, 4)
(1, 2)                 < (1, 2, -1)
(1, 2, 3)             == (1.0, 2.0, 3.0)
(1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)

Man beachte, daß es erlaubt ist, Objekte verschiedenen Typs zu vergleichen. Das Resultat ist deterministisch, aber beliebig: die Typen sind nach ihrem Namen geordnet. Daher ist eine Liste immer kleiner als ein String, ein String immer kleiner als ein Tupel, etc. Gemischte numerische Typen werden nach ihrem numerischen Wert verglichen, d.h. 0 ist gleich 0.0, etc.5.1



Fußnoten

... etc.5.1
Man sollte sich nicht auf diese Regeln verlassen, da sie sich in einer zukünftigen Version der Sprache ändern könnten.


Send comments to python-docs@python.org.