5. Datenstrukturen
******************

In diesem Kapitel werden einige Dinge, die du bereits kennengelernt
hast, näher erläutert, und es werden zudem einige neue Aspekte
hinzugefügt.


5.1. Mehr zum Thema Listen
==========================

The list data type has some more methods.  Here are all of the methods
of list objects:

list.append(x)

   Add an item to the end of the list.  Equivalent to "a[len(a):] =
   [x]".

list.extend(iterable)

   Extend the list by appending all the items from the iterable.
   Equivalent to "a[len(a):] = iterable".

list.insert(i, x)

   Fügt ein Element an einer bestimmten Position ein. Das erste
   Argument ist der Index des Elements, vor dem eingefügt werden soll.
   Daher fügt "a.insert(0, x)" am Anfang der Liste ein, und
   "a.insert(len(a), x)" entspricht "a.append(x)".

list.remove(x)

   Remove the first item from the list whose value is equal to *x*.
   It raises a "ValueError" if there is no such item.

list.pop([i])

   Remove the item at the given position in the list, and return it.
   If no index is specified, "a.pop()" removes and returns the last
   item in the list.  (The square brackets around the *i* in the
   method signature denote that the parameter is optional, not that
   you should type square brackets at that position.  You will see
   this notation frequently in the Python Library Reference.)

list.clear()

   Remove all items from the list.  Equivalent to "del a[:]".

list.index(x[, start[, end]])

   Return zero-based index in the list of the first item whose value
   is equal to *x*. Raises a "ValueError" if there is no such item.

   Die optionalen Argumente *start* und *end* werden wie in der Slice-
   Notation interpretiert und dienen dazu, die Suche auf eine
   bestimmte Teilfolge der Liste zu beschränken. Der zurückgegebene
   Index wird relativ zum Anfang der vollständigen Folge und nicht
   relativ zum Argument *start* berechnet.

list.count(x)

   Return the number of times *x* appears in the list.

list.sort(*, key=None, reverse=False)

   Sortiere die Elemente der Liste an Ort und Stelle (die Argumente
   können zur Anpassung der Sortierung verwendet werden; eine
   Erläuterung findest du unter "sorted()" ).

list.reverse()

   Die Elemente der Liste an Ort und Stelle in umgekehrter Reihenfolge
   anordnen.

list.copy()

   Return a shallow copy of the list.  Equivalent to "a[:]".

Ein Beispiel, das die meisten Methoden der Liste verwendet:

   >>> fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
   >>> fruits.count('apple')
   2
   >>> fruits.count('tangerine')
   0
   >>> fruits.index('banana')
   3
   >>> fruits.index('banana', 4)  # Find next banana starting a position 4
   6
   >>> fruits.reverse()
   >>> fruits
   ['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange']
   >>> fruits.append('grape')
   >>> fruits
   ['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange', 'grape']
   >>> fruits.sort()
   >>> fruits
   ['apple', 'apple', 'banana', 'banana', 'grape', 'kiwi', 'orange', 'pear']
   >>> fruits.pop()
   'pear'

Vielleicht ist dir aufgefallen, dass bei Methoden wie "insert",
"remove" oder "sort", die lediglich die Liste verändern, kein
Rückgabewert ausgegeben wird – sie geben den Standardwert "None"
zurück. [1] Dies ist ein Entwurfsprinzip für alle veränderbaren
Datenstrukturen in Python.

Another thing you might notice is that not all data can be sorted or
compared.  For instance, "[None, 'hello', 10]" doesn't sort because
integers can't be compared to strings and *None* can't be compared to
other types.  Also, there are some types that don't have a defined
ordering relation.  For example, "3+4j < 5+7j" isn't a valid
comparison.


5.1.1. Listen als Stapel verwenden
----------------------------------

The list methods make it very easy to use a list as a stack, where the
last element added is the first element retrieved ("last-in, first-
out").  To add an item to the top of the stack, use "append()".  To
retrieve an item from the top of the stack, use "pop()" without an
explicit index.  For example:

   >>> stack = [3, 4, 5]
   >>> stack.append(6)
   >>> stack.append(7)
   >>> stack
   [3, 4, 5, 6, 7]
   >>> stack.pop()
   7
   >>> stack
   [3, 4, 5, 6]
   >>> stack.pop()
   6
   >>> stack.pop()
   5
   >>> stack
   [3, 4]


5.1.2. Listen als Warteschlangen verwenden
------------------------------------------

It is also possible to use a list as a queue, where the first element
added is the first element retrieved ("first-in, first-out"); however,
lists are not efficient for this purpose.  While appends and pops from
the end of list are fast, doing inserts or pops from the beginning of
a list is slow (because all of the other elements have to be shifted
by one).

Um eine Warteschlange zu implementieren, verwende "collections.deque",
das für schnelles Hinzufügen und Entnehmen von beiden Enden ausgelegt
ist.  Beispiel:

   >>> from collections import deque
   >>> queue = deque(["Eric", "John", "Michael"])
   >>> queue.append("Terry")           # Terry arrives
   >>> queue.append("Graham")          # Graham arrives
   >>> queue.popleft()                 # The first to arrive now leaves
   'Eric'
   >>> queue.popleft()                 # The second to arrive now leaves
   'John'
   >>> queue                           # Remaining queue in order of arrival
   deque(['Michael', 'Terry', 'Graham'])


5.1.3. Listen-Abstraktion
-------------------------

Listen-Abstraktion bieten eine prägnante Möglichkeit, Listen zu
erstellen. Häufige Anwendungsfälle sind die Erstellung neuer Listen,
bei denen jedes Element das Ergebnis bestimmter Operationen ist, die
auf jedes Element einer anderen Sequenz oder eines anderen
iterierbaren Objekts angewendet werden, oder die Erstellung einer
Teilsequenz aus den Elementen, die eine bestimmte Bedingung erfüllen.

Nehmen wir zum Beispiel an, wir möchten eine Liste von Quadraten
erstellen, etwa wie folgt:

   >>> squares = []
   >>> for x in range(10):
   ...     squares.append(x**2)
   ...
   >>> squares
   [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Beachte, dass dadurch eine Variable namens "x" angelegt (oder
überschrieben) wird, die auch nach Abschluss der Schleife noch
vorhanden ist. Wir können die Liste der Quadrate ohne Nebenwirkungen
wie folgt berechnen:

   squares = list(map(lambda x: x**2, range(10)))

oder, gleichbedeutend:

   squares = [x**2 for x in range(10)]

was prägnanter und besser lesbar ist.

Eine Listenkomprimierung besteht aus Klammern, die einen Ausdruck
enthalten, gefolgt von einer "for"-Klausel und anschließend null oder
mehr "for"- oder "if"-Klauseln. Das Ergebnis ist eine neue Liste, die
sich aus der Auswertung des Ausdrucks im Kontext der darauf folgenden
"for"- und "if"-Klauseln ergibt. Diese Listenkomprimierung kombiniert
beispielsweise die Elemente zweier Listen, sofern sie nicht identisch
sind:

   >>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
   [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

und das entspricht:

   >>> combs = []
   >>> for x in [1,2,3]:
   ...     for y in [3,1,4]:
   ...         if x != y:
   ...             combs.append((x, y))
   ...
   >>> combs
   [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Beachte, dass die Reihenfolge der Anweisungen "for" und "if" in beiden
Codeausschnitten identisch ist.

Wenn es sich bei dem Ausdruck um ein Tupel handelt (z. B. "(x, y)" im
vorherigen Beispiel), muss es in Klammern gesetzt werden.

   >>> vec = [-4, -2, 0, 2, 4]
   >>> # create a new list with the values doubled
   >>> [x*2 for x in vec]
   [-8, -4, 0, 4, 8]
   >>> # filter the list to exclude negative numbers
   >>> [x for x in vec if x >= 0]
   [0, 2, 4]
   >>> # apply a function to all the elements
   >>> [abs(x) for x in vec]
   [4, 2, 0, 2, 4]
   >>> # call a method on each element
   >>> freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
   >>> [weapon.strip() for weapon in freshfruit]
   ['banana', 'loganberry', 'passion fruit']
   >>> # create a list of 2-tuples like (number, square)
   >>> [(x, x**2) for x in range(6)]
   [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
   >>> # the tuple must be parenthesized, otherwise an error is raised
   >>> [x, x**2 for x in range(6)]
     File "<stdin>", line 1
       [x, x**2 for x in range(6)]
        ^^^^^^^
   SyntaxError: did you forget parentheses around the comprehension target?
   >>> # flatten a list using a listcomp with two 'for'
   >>> vec = [[1,2,3], [4,5,6], [7,8,9]]
   >>> [num for elem in vec for num in elem]
   [1, 2, 3, 4, 5, 6, 7, 8, 9]

Listen-Abstraktionen können komplexe Ausdrücke und verschachtelte
Funktionen enthalten:

   >>> from math import pi
   >>> [str(round(pi, i)) for i in range(1, 6)]
   ['3.1', '3.14', '3.142', '3.1416', '3.14159']


5.1.4. Verschachtelte Listen-Abstraktion
----------------------------------------

Der erste Ausdruck in einer Listen-Abstraktion kann ein beliebiger
Ausdruck sein, einschließlich einer weiteren Listen-Abstraktion.

Betrachte das folgende Beispiel einer 3×4-Matrix, die als Liste aus
drei Listen der Länge 4 implementiert ist:

   >>> matrix = [
   ...     [1, 2, 3, 4],
   ...     [5, 6, 7, 8],
   ...     [9, 10, 11, 12],
   ... ]

Die folgende Listen-Abstraktion transponiert Zeilen und Spalten:

   >>> [[row[i] for row in matrix] for i in range(4)]
   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

As we saw in the previous section, the nested listcomp is evaluated in
the context of the "for" that follows it, so this example is
equivalent to:

   >>> transposed = []
   >>> for i in range(4):
   ...     transposed.append([row[i] for row in matrix])
   ...
   >>> transposed
   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

was wiederum dasselbe ist wie:

   >>> transposed = []
   >>> for i in range(4):
   ...     # the following 3 lines implement the nested listcomp
   ...     transposed_row = []
   ...     for row in matrix:
   ...         transposed_row.append(row[i])
   ...     transposed.append(transposed_row)
   ...
   >>> transposed
   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

In der Praxis solltest du integrierte Funktionen komplexen
Ablaufanweisungen vorziehen. Die Funktion "zip()" eignet sich
hervorragend für diesen Anwendungsfall:

   >>> list(zip(*matrix))
   [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

Weitere Informationen zum Sternchen in dieser Zeile findest du unter
Entpacken von Argumentlisten.


5.2. Die Erklärung der "del"
============================

There is a way to remove an item from a list given its index instead
of its value: the "del" statement.  This differs from the "pop()"
method which returns a value.  The "del" statement can also be used to
remove slices from a list or clear the entire list (which we did
earlier by assignment of an empty list to the slice).  For example:

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

"del" kann auch zum Löschen ganzer Variablen verwendet werden:

   >>> del a

Der Verweis auf den Namen "a" ist hier ein Fehler (zumindest solange,
bis ihm ein anderer Wert zugewiesen wird). Wir werden später noch
weitere Verwendungsmöglichkeiten für "del" finden.


5.3. Tupel und Sequenzen
========================

Wir haben gesehen, dass Listen und Zeichenketten viele gemeinsame
Eigenschaften haben, wie beispielsweise Indizierungs- und
Ausschnittoperationen. Sie sind zwei Beispiele für
*Sequenz*-Datentypen (siehe Sequence Types --- list, tuple, range). Da
Python eine sich weiterentwickelnde Sprache ist, können weitere
Sequenz-Datentypen hinzukommen. Es gibt außerdem einen weiteren
standardmäßigen Sequenz-Datentyp: das *Tupel*.

Ein Tupel besteht aus einer Reihe von Werten, die durch Kommas
getrennt sind, zum Beispiel:

   >>> t = 12345, 54321, 'hello!'
   >>> t[0]
   12345
   >>> t
   (12345, 54321, 'hello!')
   >>> # Tuples may be nested:
   ... u = t, (1, 2, 3, 4, 5)
   >>> u
   ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
   >>> # Tuples are immutable:
   ... t[0] = 88888
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: 'tuple' object does not support item assignment
   >>> # but they can contain mutable objects:
   ... v = ([1, 2, 3], [3, 2, 1])
   >>> v
   ([1, 2, 3], [3, 2, 1])

Wie du siehst, werden Tupel in der Ausgabe immer in Klammern gesetzt,
damit verschachtelte Tupel korrekt interpretiert werden; sie können
mit oder ohne umschließende Klammern eingegeben werden, obwohl
Klammern oft ohnehin erforderlich sind (wenn das Tupel Teil eines
größeren Ausdrucks ist).  Es ist nicht möglich, den einzelnen
Elementen eines Tupels Werte zuzuweisen; es ist jedoch möglich, Tupel
zu erstellen, die veränderbare Objekte wie beispielsweise Listen
enthalten.

Auch wenn Tupel auf den ersten Blick Listen ähneln mögen, werden sie
oft in anderen Situationen und für andere Zwecke verwendet. Tupel sind
*unveränderlich* und enthalten in der Regel eine heterogene Folge von
Elementen, auf die über Entpacken (siehe weiter unten in diesem
Abschnitt) oder Indizierung (oder im Fall von "namedtuples" sogar über
Attribute) zugegriffen wird. Listen sind *veränderlich*, und ihre
Elemente sind in der Regel homogen; der Zugriff erfolgt durch
Iteration über die Liste.

Ein besonderes Problem stellt die Bildung von Tupeln dar, die 0 oder 1
Element enthalten: Die Syntax weist hierfür einige zusätzliche
Besonderheiten auf.  Leere Tupel werden durch ein leeres Klammerpaar
gebildet; ein Tupel mit einem Element wird gebildet, indem man einem
Wert ein Komma nachsetzt (es reicht nicht aus, einen einzelnen Wert in
Klammern zu setzen). Unschön, aber effektiv.  Zum Beispiel:

   >>> empty = ()
   >>> singleton = 'hello',    # <-- note trailing comma
   >>> len(empty)
   0
   >>> len(singleton)
   1
   >>> singleton
   ('hello',)

Die Anweisung "t = 12345, 54321, 'hello!'" ist ein Beispiel für
*Tupel-Packing*: Die Werte "12345", "54321" und "'hello!'" werden in
einem Tupel zusammengefasst. Auch die umgekehrte Operation ist
möglich:

   >>> x, y, z = t

Dies wird passenderweise als *Sequenz-Entpackung* bezeichnet und
funktioniert für jede beliebige Sequenz auf der rechten Seite. Für die
Sequenz-Entpackung muss die Anzahl der Variablen auf der linken Seite
des Gleichheitszeichens der Anzahl der Elemente in der Sequenz
entsprechen.  Beachte, dass die Mehrfachzuweisung im Grunde nur eine
Kombination aus Tupel-Packing und Sequenz-Unpacking ist.


5.4. Sets
=========

Python also includes a data type for *sets*.  A set is an unordered
collection with no duplicate elements.  Basic uses include membership
testing and eliminating duplicate entries.  Set objects also support
mathematical operations like union, intersection, difference, and
symmetric difference.

Zum Erstellen von Mengen können geschweifte Klammern oder die Funktion
"set()" verwendet werden. Hinweis: Um eine leere Menge zu erstellen,
müssen Sie "set()" verwenden, nicht "{}"; Letzteres erstellt ein
leeres Wörterbuch, eine Datenstruktur, die wir im nächsten Abschnitt
behandeln.

Hier eine kurze Demonstration:

   >>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
   >>> print(basket)                      # show that duplicates have been removed
   {'orange', 'banana', 'pear', 'apple'}
   >>> 'orange' in basket                 # fast membership testing
   True
   >>> 'crabgrass' in basket
   False

   >>> # Demonstrate set operations on unique letters from two words
   ...
   >>> a = set('abracadabra')
   >>> b = set('alacazam')
   >>> a                                  # unique letters in a
   {'a', 'r', 'b', 'c', 'd'}
   >>> a - b                              # letters in a but not in b
   {'r', 'd', 'b'}
   >>> a | b                              # letters in a or b or both
   {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
   >>> a & b                              # letters in both a and b
   {'a', 'c'}
   >>> a ^ b                              # letters in a or b but not both
   {'r', 'd', 'b', 'm', 'z', 'l'}

Ähnlich wie bei den Listenkomprimierungen werden auch
Mengekomprimierungen unterstützt:

   >>> a = {x for x in 'abracadabra' if x not in 'abc'}
   >>> a
   {'r', 'd'}


5.5. Wörterbücher
=================

Another useful data type built into Python is the *dictionary* (see
Mapping Types --- dict). Dictionaries are sometimes found in other
languages as "associative memories" or "associative arrays".  Unlike
sequences, which are indexed by a range of numbers, dictionaries are
indexed by *keys*, which can be any immutable type; strings and
numbers can always be keys.  Tuples can be used as keys if they
contain only strings, numbers, or tuples; if a tuple contains any
mutable object either directly or indirectly, it cannot be used as a
key. You can't use lists as keys, since lists can be modified in place
using index assignments, slice assignments, or methods like "append()"
and "extend()".

Man kann sich ein Wörterbuch am besten als eine Menge von
*Schlüssel:Wert*-Paaren vorstellen, wobei die Schlüssel (innerhalb
eines Wörterbuchs) eindeutig sein müssen. Ein Paar geschweifter
Klammern erstellt ein leeres Wörterbuch: "{}". Durch Einfügen einer
durch Kommas getrennten Liste von Schlüssel:Wert-Paaren innerhalb der
geschweiften Klammern werden dem Wörterbuch anfängliche Schlüssel
:Wert-Paare hinzugefügt; auf diese Weise werden Wörterbücher auch bei
der Ausgabe dargestellt.

The main operations on a dictionary are storing a value with some key
and extracting the value given the key.  It is also possible to delete
a key:value pair with "del". If you store using a key that is already
in use, the old value associated with that key is forgotten.  It is an
error to extract a value using a non-existent key.

Wendet man "list(d)" auf ein Wörterbuch an, wird eine Liste aller im
Wörterbuch verwendeten Schlüssel in der Reihenfolge ihrer Einfügung
zurückgegeben (wenn du die Liste sortiert haben möchtest, verwende
stattdessen einfach "sorted(d)"). Um zu prüfen, ob ein einzelner
Schlüssel im Wörterbuch enthalten ist, verwende das Schlüsselwort "in"
.

Hier ist ein kleines Beispiel, bei dem ein Wörterbuch verwendet wird:

   >>> tel = {'jack': 4098, 'sape': 4139}
   >>> tel['guido'] = 4127
   >>> tel
   {'jack': 4098, 'sape': 4139, 'guido': 4127}
   >>> tel['jack']
   4098
   >>> del tel['sape']
   >>> tel['irv'] = 4127
   >>> tel
   {'jack': 4098, 'guido': 4127, 'irv': 4127}
   >>> list(tel)
   ['jack', 'guido', 'irv']
   >>> sorted(tel)
   ['guido', 'irv', 'jack']
   >>> 'guido' in tel
   True
   >>> 'jack' not in tel
   False

Der Konstruktor "dict()" erstellt Wörterbücher direkt aus Sequenzen
von Schlüssel-Wert-Paaren:

   >>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
   {'sape': 4139, 'guido': 4127, 'jack': 4098}

Darüber hinaus können Dict-Comprehensions verwendet werden, um
Wörterbücher aus beliebigen Schlüssel- und Wert-Ausdrücken zu
erstellen:

   >>> {x: x**2 for x in (2, 4, 6)}
   {2: 4, 4: 16, 6: 36}

Wenn es sich bei den Schlüsseln um einfache Zeichenfolgen handelt, ist
es manchmal einfacher, Paare mithilfe von Schlüsselwortargumenten
anzugeben:

   >>> dict(sape=4139, guido=4127, jack=4098)
   {'sape': 4139, 'guido': 4127, 'jack': 4098}


5.6. Schleifentechniken
=======================

When looping through dictionaries, the key and corresponding value can
be retrieved at the same time using the "items()" method.

   >>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
   >>> for k, v in knights.items():
   ...     print(k, v)
   ...
   gallahad the pure
   robin the brave

Beim Durchlaufen einer Sequenz können der Positionsindex und der
zugehörige Wert mithilfe der Funktion "enumerate()" gleichzeitig
abgerufen werden.

   >>> for i, v in enumerate(['tic', 'tac', 'toe']):
   ...     print(i, v)
   ...
   0 tic
   1 tac
   2 toe

Um zwei oder mehr Sequenzen gleichzeitig zu durchlaufen, können die
Einträge mit der Funktion "zip()" gepaart werden.

   >>> questions = ['name', 'quest', 'favorite color']
   >>> answers = ['lancelot', 'the holy grail', 'blue']
   >>> for q, a in zip(questions, answers):
   ...     print('What is your {0}?  It is {1}.'.format(q, a))
   ...
   What is your name?  It is lancelot.
   What is your quest?  It is the holy grail.
   What is your favorite color?  It is blue.

Um eine Folge in umgekehrter Reihenfolge zu durchlaufen, gib zunächst
die Folge in Vorwärtsrichtung an und rufe anschließend die Funktion
"reversed()" auf.

   >>> for i in reversed(range(1, 10, 2)):
   ...     print(i)
   ...
   9
   7
   5
   3
   1

Um eine Folge in sortierter Reihenfolge zu durchlaufen, verwende die
Funktion "sorted()", die eine neue sortierte Liste zurückgibt, während
die Quelle unverändert bleibt.

   >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
   >>> for i in sorted(basket):
   ...     print(i)
   ...
   apple
   apple
   banana
   orange
   orange
   pear

Die Anwendung von "set()" auf eine Sequenz entfernt doppelte Elemente.
Die Verwendung von "sorted()" in Kombination mit "set()" auf eine
Sequenz ist eine gängige Methode, um die eindeutigen Elemente der
Sequenz in sortierter Reihenfolge durchzugehen.

   >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
   >>> for f in sorted(set(basket)):
   ...     print(f)
   ...
   apple
   banana
   orange
   pear

Manchmal ist es verlockend, eine Liste zu ändern, während man sie in
einer Schleife durchläuft; oft ist es jedoch einfacher und sicherer,
stattdessen eine neue Liste zu erstellen.

   >>> import math
   >>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
   >>> filtered_data = []
   >>> for value in raw_data:
   ...     if not math.isnan(value):
   ...         filtered_data.append(value)
   ...
   >>> filtered_data
   [56.2, 51.7, 55.3, 52.5, 47.8]


5.7. Mehr zu den Bedingungen
============================

Die in den Anweisungen "while" und "if" verwendeten Bedingungen können
beliebige Operatoren enthalten, nicht nur Vergleichsoperatoren.

Die Vergleichsoperatoren "in" und "not in" sind
Zugehörigkeitsprüfungen, die feststellen, ob ein Wert in einem
Container enthalten ist (oder nicht). Die Operatoren "is" und "is not"
vergleichen, ob zwei Objekte tatsächlich dasselbe Objekt sind. Alle
Vergleichsoperatoren haben dieselbe Priorität, die niedriger ist als
die aller numerischen Operatoren.

Vergleiche können verkettet werden. Beispielsweise prüft "a < b == c",
ob "a" kleiner ist als "b" und ob darüber hinaus "b" gleich "c" ist.

Vergleiche können mithilfe der Booleschen Operatoren "and" und "or"
kombiniert werden, und das Ergebnis eines Vergleichs (oder eines
beliebigen anderen Booleschen Ausdrucks) kann mit "not" negiert
werden. Diese haben eine niedrigere Priorität als
Vergleichsoperatoren; unter ihnen hat "not" die höchste Priorität und
"or" die niedrigste, sodass "A and not B or C" gleichbedeutend ist mit
"(A and (not B)) or C". Wie immer können Klammern verwendet werden, um
die gewünschte Zusammensetzung auszudrücken.

Die Booleschen Operatoren "and" und "or" sind sogenannte
*Kurzschluss*-Operatoren: Deine Argumente werden von links nach rechts
ausgewertet, und die Auswertung wird beendet, sobald das Ergebnis
feststeht.  Sind beispielsweise "A" und "C" wahr, "B" jedoch falsch,
so wertet "A and B and C" den Ausdruck "C" nicht aus.  Wird ein
Kurzschlussoperator als allgemeiner Wert und nicht als Boolescher Wert
verwendet, ist der Rückgabewert das zuletzt ausgewertete Argument.

Es ist möglich, das Ergebnis eines Vergleichs oder eines anderen
booleschen Ausdrucks einer Variablen zuzuweisen.  Beispiel:

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

Beachte dass in Python – anders als in C – Zuweisungen innerhalb von
Ausdrücken explizit mit dem Walross-Operator ":=" erfolgen müssen.
Dadurch wird eine häufige Problemklasse vermieden, die in C-Programmen
auftritt: die Eingabe von "=" in einem Ausdruck, obwohl eigentlich
"==" gemeint war.


5.8. Vergleich von Sequenzen und anderen Typen
==============================================

Sequenzobjekte können in der Regel mit anderen Objekten desselben
Sequenztyps verglichen werden. Der Vergleich erfolgt nach
*lexikografischer* Reihenfolge: Zunächst werden die ersten beiden
Elemente verglichen; unterscheiden sie sich, bestimmt dies das
Ergebnis des Vergleichs; sind sie gleich, werden die nächsten beiden
Elemente verglichen und so weiter, bis eine der beiden Sequenzen
erschöpft ist. Sind zwei zu vergleichende Elemente selbst Sequenzen
desselben Typs, wird der lexikografische Vergleich rekursiv
durchgeführt. Sind alle Elemente zweier Sequenzen gleich, gelten die
Sequenzen als gleich. Ist eine Sequenz eine anfängliche Teilsequenz
der anderen, ist die kürzere Sequenz die kleinere (geringere).  Bei
der lexikografischen Sortierung von Zeichenketten wird die Unicode-
Codepunktnummer zur Sortierung einzelner Zeichen verwendet. Einige
Beispiele für Vergleiche zwischen Sequenzen desselben 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)

Beachte, dass der Vergleich von Objekten unterschiedlicher Typen mit
"<" oder ">" zulässig ist, sofern die Objekte über entsprechende
Vergleichsmethoden verfügen. Beispielsweise werden gemischte
numerische Typen anhand ihres numerischen Werts verglichen, sodass 0
gleich 0,0 ist usw. Andernfalls liefert der Interpreter keine
willkürliche Reihenfolge, sondern löst eine "TypeError"-Ausnahme aus.

-[ Fußnoten ]-

[1] Andere Sprachen geben möglicherweise das geänderte Objekt zurück,
    was eine Methodenverkettung ermöglicht, wie beispielsweise
    "d->insert("a")->remove("b")->sort();".
