13 Sequenzielle Datentypen 

Unter sequenziellen Datentypen wird eine Klasse von Datentypen zusammengefasst, die Folgen von gleichartigen oder verschiedenen Elementen verwalten. Die in sequenziellen Datentypen gespeicherten Elemente haben eine definierte Reihenfolge, und man kann über eindeutige Indizes auf sie zugreifen.
Python stellt im Wesentlichen die folgenden fünf sequenziellen Typen zur Verfügung: str, bytes, bytearray, list und tuple.
Datentyp | speichert | Veränderlichkeit | Abschnitt |
---|---|---|---|
list | Listen beliebiger Instanzen | veränderlich | Abschnitt 13.2 |
tuple | Listen beliebiger Instanzen | unveränderlich | Abschnitt 13.3 |
str | Text als Sequenz von Buchstaben | unveränderlich | Abschnitt 13.4 |
bytes | Binärdaten als Sequenz von Bytes | unveränderlich | Abschnitt 13.4 |
bytearray | Binärdaten als Sequenz von Bytes | veränderlich | Abschnitt 13.4 |
Tabelle 13.1 Liste der sequenziellen Datentypen
Der Datentyp str ist für die Speicherung und Verarbeitung von Texten vorgesehen. Daher besteht eine str-Instanz aus einer Folge von Buchstaben, Leer- und Interpunktionszeichen sowie Zeilenvorschüben – also genau den Bausteinen, aus denen Texte in menschlicher Sprache bestehen. Bemerkenswert ist dabei, dass dies auch mit regionalen Sonderzeichen wie beispielsweise den deutschen Umlauten »ä«, »ü« und »ö« funktioniert.
Im Gegensatz dazu kann eine Instanz des Datentyps bytes einen binären Datenstrom, also eine Folge von Bytes, speichern. Der Datentyp bytearray ist ebenfalls in der Lage, Binärdaten zu speichern. Allerdings sind bytearray-Instanzen anders als bytes-Instanzen veränderlich.
Die strukturelle Trennung von Textdaten und Binärdaten ist eine Eigenschaft, die Python von vielen anderen Programmiersprachen unterscheidet.
[»] Hinweis
Dies ist eine der großen Neuerungen ab Python 3.0. In früheren Python-Versionen gab es die beiden Datentypen str und unicode, wobei str dem jetzigen bytes und unicode dem jetzigen str entsprach. Da häufig der alte Datentyp str zum Speichern von Text-Strings genutzt wurde, gab es einige Stolpersteine, wenn man Sonderzeichen mit Python-Programmen verarbeiten wollte. Durch die neue Typaufteilung ist der Umgang mit Zeichenketten klarer strukturiert. Allerdings muss man darauf achten, welchen Datentyp Funktionen der Standardbibliothek als Parameter erwarten bzw. als Rückgabewert zurückgeben, und gegebenenfalls Umwandlungen vornehmen.
Mehr dazu erfahren Sie in Abschnitt 13.4.4, »Zeichensätze und Sonderzeichen«.
Sowohl Instanzen des Datentyps str als auch des Datentyps bytes sind immutabel, ihr Wert kann sich nach der Instanziierung also nicht mehr verändern. Trotzdem können Sie komfortabel mit Strings arbeiten. Bei Änderungen wird nur nicht der Ursprungsstring verändert, sondern stets ein neuer String erzeugt.
Die Typen list und tuple können Folgen beliebiger Instanzen speichern. Der wesentliche Unterschied zwischen den beiden fast identischen Datentypen ist, dass eine Liste nach ihrer Erzeugung verändert werden kann, während ein Tupel keine Änderung des Anfangsinhalts zulässt: list ist ein mutabler, tuple ein immutabler Datentyp.
Für jede Instanz eines sequenziellen Datentyps gibt es einen Grundstock von Operatoren und Methoden, der immer verfügbar ist. Der Einfachheit halber werden wir diesen allgemein am Beispiel von list- und str-Instanzen einführen und erst in den folgenden Abschnitten Besonderheiten bezüglich der einzelnen Datentypen aufzeigen.
13.1 Operationen auf Instanzen sequenzieller Datentypen 

Für alle sequenziellen Datentypen sind folgende Operationen definiert (s und t sind dabei Instanzen desselben sequenziellen Datentyps; i, j, k und n sind ganze Zahlen; x ist eine Referenz auf eine beliebige Instanz):
Notation | Beschreibung | Abschnitt |
---|---|---|
x in s | Prüft, ob x in s enthalten ist. Das Ergebnis ist ein Wahrheitswert. | Abschnitt 13.1.1 |
x not in s | Prüft, ob x nicht in s enthalten ist. Das Ergebnis ist eine bool-Instanz. Gleichwertig mit not x in s. | Abschnitt 13.1.1 |
s + t | Das Ergebnis ist eine neue Sequenz, die die Verkettung von s und t enthält. | Abschnitt 13.1.2 |
s += t | Erzeugt die Verkettung von s und t und weist sie s zu. | Abschnitt 13.1.2 |
s * n oder n * s | Liefert eine neue Sequenz, die die Verkettung von n Kopien von s enthält. | Abschnitt 13.1.3 |
s *= n | Erzeugt das Produkt s * n und weist es s zu. | Abschnitt 13.1.3 |
s[i] | Liefert das i-te Element von s. | Abschnitt 13.1.4 |
s[i:j] | Liefert den Ausschnitt aus s von i bis j. | Abschnitt 13.1.4 |
s[i:j:k] | Liefert den Ausschnitt aus s von i bis j, wobei nur jedes k-te Element beachtet wird. | Abschnitt 13.1.4 |
len(s) | Gibt die Anzahl der Elemente von s zurück. | Abschnitt 13.1.5 |
max(s) | Liefert das größte Element von s, sofern eine Ordnungsrelation für die Elemente definiert ist. | Abschnitt 13.1.6 |
min(s) | Liefert das kleinste Element von s, sofern eine Ordnungsrelation für die Elemente definiert ist. | Abschnitt 13.1.6 |
s.index(x[, i[, j]]) | Gibt den Index k des ersten Vorkommens von x in der Sequenz s im Bereich i ≤ k < j zurück. | Abschnitt 13.1.7 |
s.count(x) | Zählt, wie oft x in der Sequenz s vorkommt. | Abschnitt 13.1.8 |
Tabelle 13.2 Operationen auf Instanzen sequenzieller Datentypen
Im Folgenden werden diese Operationen im Detail erklärt.
13.1.1 Ist ein Element vorhanden? – die Operatoren in und not in 

Mithilfe von in lässt sich ermitteln, ob ein bestimmtes Element in einer Sequenz enthalten ist. Für eine Instanz des Datentyps list, die sowohl Strings als auch Zahlen enthält, sieht das folgendermaßen aus:
>>> lst = ["eins", 2, 3.0, "vier", 5, "sechs", "sieben"]
>>> 3.0 in lst
True
>>> "vier" in lst
True
>>> 10 in lst
False
Da die Elemente eines Strings Zeichen sind, können wir mit dem Operator prüfen, ob ein bestimmter Buchstabe in einem String vorkommt. Als Ergebnis wird ein Wahrheitswert geliefert: True, wenn das Element vorhanden ist, und False, wenn es nicht vorhanden ist. Zeichen können Sie in Python durch Strings der Länge 1 abbilden:
>>> s = "Dies ist unser Test-String"
>>> "u" in s
True
>>> if "j" in s:
... print("Juhuu, mein Lieblingsbuchstabe ist enthalten")
... else:
... print("Ich mag diesen String nicht ...")
Ich mag diesen String nicht ...
Es ist außerdem möglich, mit dem in-Operator zu prüfen, ob ein bestimmter Teil-String in einer Zeichenkette enthalten ist:
>>> s = "Dies ist unser Test-String"
>>> "ist" in s
True
>>> "Hallo" in s
False
Das funktioniert nur mit Zeichenketten, also Instanzen der Typen str, bytes und bytearray. Mit dem in-Operator kann nicht geprüft werden, ob eine Teilliste in einer list-Instanz enthalten ist. Das Gleiche gilt für Instanzen des Typs tuple.
>>> [2,3] in [1,2,3,4]
False
Um das Gegenteil zu prüfen – also ob ein Element nicht in einer Sequenz enthalten ist –, dient der Operator not in. Seine Verwendung entspricht der des in-Operators, mit dem einzigen Unterschied, dass er das negierte Ergebnis des in-Operators produziert:
>>> "a" in "Besuch beim Zahnarzt"
True
>>> "a" not in "Besuch beim Zahnarzt"
False
Sie werden sich an dieser Stelle zu Recht fragen, warum für diesen Zweck ein eigener Operator definiert worden ist, wo man doch mit not jeden booleschen Wert negieren kann. Folgende Überprüfungen sind gleichwertig:
>>> "n" not in "Python ist toll"
False
>>> not "n" in "Python ist toll"
False
Der Grund für diese scheinbar überflüssige Definition liegt in der besseren Lesbarkeit. Der Ausdruck x not in s liest sich im Gegensatz zu not x in s genau wie ein englischer Satz, während die andere Form schwieriger zu lesen ist[ 40 ](Zusätzlich müssen Sie für die Interpretation von not x in s die Priorität der beiden Operatoren not bzw. in kennen. Wenn der not-Operator stärker bindet, würde der Ausdruck wie (not x) in s ausgewertet. Hat in eine höhere Priorität, wäre der Ausdruck wie not (x in s) zu behandeln. Tatsächlich bindet in stärker als not, womit letztere Deutung die richtige ist. ).
13.1.2 Verkettung von Sequenzen – die Operatoren + und += 

Um Sequenzen zu verketten, wird der +-Operator verwendet. Im Beispiel werden Vor- und Nachname von Herrn Meier zusammen mit einem Leerzeichen zu einem neuen String verkettet:
>>> vorname = "Heinz"
>>> nachname = "Meier"
>>> name = vorname + " " + nachname
>>> name
'Heinz Meier'
Eine weitere Möglichkeit, Strings zu verketten, bietet der Operator += für erweiterte Zuweisungen:
>>> s = "Musik"
>>> t = "lautsprecher"
>>> s += t
>>> s
'Musiklautsprecher'
Dabei ist s += t für immutable Datentypen genauso zu lesen wie s = s + t, denn es wird tatsächlich eine neue Instanz mit dem Wert von s + t erzeugt, die dann von s referenziert wird. Es existieren also nach der Operation s += t die drei Instanzen "Musik", "lautsprecher" und "Musiklautsprecher" im Speicher, wobei es keine Referenz mehr auf "Musik" gibt.
Für mutable Datentypen wie beispielsweise list gilt das nicht. Hier wird keine weitere Instanz mit dem Wert s + t erzeugt, sondern die Instanz s verändert.
Zwei Beispiele verdeutlichen diesen Unterschied zwischen mutablen und immutablen Datentypen:
>>> s = "Musik"
>>> t = "lautsprecher"
>>> temp = s
>>> s += t
>>> s
'Musiklautsprecher'
>>> t
'lautsprecher'
>>> temp
'Musik'
Da mit der Anweisung s += t eine neue str-Instanz erzeugt wurde, hat sich die von temp referenzierte str-Instanz nicht verändert. Anders sieht dies beim mutablen Datentyp list aus:
>>> s = [1,2]
>>> t = [3,4]
>>> temp = s
>>> s += t
>>> s
[1, 2, 3, 4]
>>> t
[3, 4]
>>> temp
[1, 2, 3, 4]
Hier verweisen s und temp auch nach der Anweisung s += t auf dieselbe list-Instanz, da die bestehende Liste verändert und kein neues Objekt erzeugt wurde.
Man sagt, der Operator += arbeitet in-place (dt. »an der Stelle«). Dies gilt im Übrigen auch für den Operator *=, der im folgenden Abschnitt behandelt wird.
13.1.3 Wiederholung von Sequenzen – die Operatoren * und *= 

Sie können das Produkt einer Sequenz s mit einer Ganzzahl n bilden: n * s oder s * n. Das Ergebnis ist eine neue Sequenz, die n Kopien von s hintereinander enthält:
>>> 3 * "abc"
'abcabcabc'
>>> "xyz" * 5
'xyzxyzxyzxyzxyz'
Wie bei der Verkettung gibt es auch hier einen Operator für die erweiterte Zuweisung, *=:
>>> weihnachtsmann = "ho"
>>> weihnachtsmann *= 3
>>> weihnachtsmann
'hohoho'
Auf die gleiche Art und Weise lassen sich auch Listen mit ganzen Zahlen multiplizieren:
>>> [1,2] * 3
[1, 2, 1, 2, 1, 2]
Der Operator *= arbeitet genauso wie += in-place. Was das genau bedeutet, haben wir im vorangegangenen Abschnitt anhand des Operators += erläutert.
13.1.4 Zugriff auf bestimmte Elemente einer Sequenz – der []-Operator 

Wie eingangs erwähnt wurde, stellen Sequenzen Folgen von Elementen dar. Da diese Elemente in einer bestimmten Reihenfolge gespeichert werden – beispielsweise wäre ein String, bei dem die Reihenfolge der Buchstaben willkürlich ist, als Speicher für Text wenig sinnvoll –, kann man jedem Element der Sequenz einen Index zuweisen. Dafür werden alle Elemente der Sequenz fortlaufend von vorn nach hinten durchnummeriert, wobei das erste Element den Index 0 bekommt.
Mit dem []-Operator können Sie auf ein bestimmtes Element der Sequenz zugreifen, indem Sie den entsprechenden Index in die eckigen Klammern schreiben:
>>> alphabet = "abcdefghijklmnopqrstuvwxyz"
>>> alphabet[9]
'j'
>>> alphabet[1]
'b'
>>> l = [1, 2, 3, 4, 5, 6]
>>> l[3]
4
Um auf das letzte oder das x-te Element von hinten zugreifen zu können, gibt es eine weitere Indizierung der Elemente von hinten nach vorn. Das letzte Element erhält dabei als Index -1, das vorletzte -2 und so weiter. Abbildung 13.1 veranschaulicht die beiden Indizierungsarten.
Abbildung 13.1 Indizierung von vorne und von hinten
>>> name = "Python"
>>> name[-2]
'o'
>>> l = [1, 2, 3, 4, 5, 6]
>>> l[-1]
6
Versuchen Sie, mit einem Index auf ein nicht vorhandenes Element zuzugreifen, wird dies mit einem IndexError quittiert:
>>> zukurz = "Ich bin zu kurz"
>>> zukurz[1337]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
Neben dem Zugriff auf einzelne Elemente der Sequenz ist es mit dem []-Operator auch möglich, ganze Teilsequenzen auszulesen. Dies erreichen Sie dadurch, dass Sie den Anfang und das Ende der gewünschten Teilfolge, durch einen Doppelpunkt getrennt, in die eckigen Klammern schreiben. Der Anfang ist dabei der Index des ersten Elements der gewünschten Teilfolge, und das Ende ist der Index des ersten Elements, das nicht mehr in der Teilfolge enthalten sein soll.
Um im folgenden Beispiel die Zeichenfolge "WICHTIG" aus dem String zu extrahieren, geben wir den Index des großen "W" und den des ersten "s" nach "WICHTIG" an:
>>> s = "schrottWICHTIGschrott"
>>> s[7]
'W'
>>> s[14]
's'
>>> s[7:14]
'WICHTIG'
Abbildung 13.2 veranschaulicht den Zugriff auf die Teilsequenz.
Abbildung 13.2 Extrahieren einer Teilsequenz
Analog extrahieren Sie Teile einer Liste:
>>> l = ["Ich", "bin", "eine", "Liste", "von", "Strings"]
>>> l[2:5]
['eine', 'Liste', 'von']
Es ist auch möglich, bei diesem sogenannten Slicing (dt. »Abschneiden«) positive und negative Indizes zu mischen. Beispielsweise ermittelt der folgende Code-Abschnitt eine Teilfolge ohne das erste und letzte Element der Ursprungssequenz:
>>> string = "ameisen"
>>> string[1:-1]
'meise'
>>> l = ["Ich", "bin", "eine", "Liste", "von", "Strings"]
>>> l[1:-1]
['bin', 'eine', 'Liste', 'von']
Die Indizes können auch weggelassen werden, was dazu führt, dass der maximal bzw. minimal mögliche Wert angenommen wird. Entfällt der Startindex, wird das nullte als erstes Element der Teilsequenz angenommen, und verzichten Sie auf den Endindex, werden alle Buchstaben bis zum Ende kopiert. Möchten Sie zum Beispiel die ersten fünf Buchstaben eines Strings oder alle ab dem fünften Zeichen ermitteln, geht das folgendermaßen:
>>> s = "abcdefghijklmnopqrstuvwxyz"
>>> s[:5]
'abcde'
>>> s[5:]
'fghijklmnopqrstuvwxyz'
Wenn Sie beide Indizes aussparen (s[:]), können Sie auch eine echte Kopie der Sequenz erzeugen, weil dann alle Elemente vom ersten bis zum letzten kopiert werden. Beachten Sie bitte die unterschiedlichen Ergebnisse der beiden folgenden Code-Ausschnitte:
>>> s1 = ["Doktorarbeit"]
>>> s2 = s1
>>> s1 == s2
True
>>> s1 is s2
True
Wie erwartet, verweisen s1 und s2 auf dieselbe Instanz, sind also identisch. Anders sieht es bei dem nächsten Beispiel aus, bei dem eine echte Kopie der Liste ["Doktorarbeit"] im Speicher erzeugt wird.[ 41 ](Im wirklichen Leben sollte man natürlich niemals eine Doktorarbeit einfach kopieren … ) Dies zeigt sich beim Identitätsvergleich mit is:
>>> s1 = ["Doktorarbeit"]
>>> s2 = s1[:]
>>> s1 == s2
True
>>> s1 is s2
False
[»] Hinweis
Wenn Sie im oben dargestellten Beispiel anstelle eines mutablen Datentyps wie list einen immutablen Datentyp wie str verwenden, kann es sein, dass in beiden Fällen der Ausdruck s1 is s2 zu True ausgewertet wird. Das liegt daran, dass es für immutable Datentypen keinen Unterschied macht, ob die Instanz wirklich kopiert oder mit der ursprünglichen Instanz gearbeitet wird: Der Wert kann ohnehin nicht verändert werden.
Daher wird eine Instanz eines immutablen Datentyps selbst bei Verwendung von [:] nicht zwingend kopiert, sondern aus Gründen der Effizienz stattdessen ein weiteres Mal referenziert.
Verwenden Sie anstelle einer Liste einen String, wird der Unterschied zum Beispiel oben deutlich:
>>> s1 = "Kopiere mich"
>>> s2 = s1[:]
>>> s2 is s1
True
Slicing bietet noch flexiblere Möglichkeiten, wenn man nicht eine ganze Teilsequenz, sondern nur bestimmte Elemente dieses Teils extrahieren möchte. Mit der Schrittweite (hier engl. step) können Sie angeben, wie die Indizes vom Beginn bis zum Ende einer Teilsequenz gezählt werden sollen. Die Schrittweite wird, durch einen weiteren Doppelpunkt abgetrennt, nach der hinteren Grenze angegeben. Eine Schrittweite von 2 sorgt beispielsweise dafür, dass nur jedes zweite Element kopiert wird:
>>> ziffern = "0123456789"
>>> ziffern[1:10:2]
'13579'
Die Zeichenfolge, die ab dem ersten, also dem mit Index Null, jedes zweite Element von ziffern enthält, ergibt einen neuen String mit den ungeraden Ziffern. Auch bei dieser erweiterten Notation können die Grenzindizes entfallen. Der folgende Code ist also zum vorangegangenen Beispiel äquivalent:
>>> ziffern = "0123456789"
>>> ziffern[1::2]
'13579'
Eine negative Schrittweite bewirkt ein Rückwärtszählen vom Start- zum Endindex, wobei in diesem Fall der Startindex auf ein weiter hinten liegendes Element der Sequenz als der Endindex verweisen muss. Mit einer Schrittweite von -1 lässt sich beispielsweise eine Sequenz »umdrehen«:
>>> name = "ytnoM Python"
>>> name[4::-1]
'Monty'
>>> name[::-1]
'nohtyP Monty'
Bei negativen Schrittweiten vertauschen sich Anfang und Ende der Sequenz. Deshalb wird in dem Beispiel name[4::-1] nicht alles vom vierten bis zum letzten Zeichen, sondern der Teil vom vierten bis zum ersten Zeichen ausgelesen.
Wichtig für den Umgang mit dem Slicing ist die Tatsache, dass zu große oder zu kleine Indizes nicht zu einem IndexError führen, wie es beim Zugriff auf einzelne Elemente der Fall ist. Zu große Indizes werden intern durch den maximal möglichen, zu kleine durch den minimal möglichen Index ersetzt. Liegen beide Indizes außerhalb des gültigen Bereichs oder ist der Startindex bei positiver Schrittweite größer als der Endindex, wird eine leere Sequenz zurückgegeben:
>>> s = "Viel weniger als 1337 Zeichen"
>>> s[5:1337]
'weniger als 1337 Zeichen'
>>> s[-100:100]
'Viel weniger als 1337 Zeichen'
>>> s[1337:2674]
''
>>> s[10:4]
''
13.1.5 Länge einer Sequenz – die Built-in Function len 

Die Anzahl der Elemente einer Sequenz definiert die Länge der Sequenz. Die Länge einer Sequenz ist eine positive ganze Zahl und lässt sich mit der Built-in Function len ermitteln:
>>> string = "Wie lang bin ich wohl?"
>>> len(string)
22
>>> len(["Hallo", 5, 2, 3, "Welt"])
5
13.1.6 Das kleinste und das größte Element einer Sequenz – min und max 

Um das kleinste beziehungsweise größte Element einer Sequenz zu ermitteln, dienen die Built-in Functions min und max.
>>> l = [5, 1, 10, -9.5, 12, -5]
>>> max(l)
12
>>> min(l)
-9.5
Allerdings sind diese beiden Funktionen nur dann sinnvoll, wenn eine Ordnungsrelation für die Elemente der Sequenz existiert. In Abschnitt 12.7 über komplexe Zahlen wird zum Beispiel der Datentyp complex ohne Ordnungsrelation beschrieben. Ebenso ist es nicht möglich, komplett verschiedene Datentypen wie beispielsweise Strings und Zahlen zu vergleichen:
>>> l = [1,2, "welt"]
>>> min(l)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'str' and 'int'
Trotzdem lassen sich min und max in sinnvoller Weise auf Strings anwenden, da für Buchstaben ihre Position im Alphabet als Ordnungsrelation benutzt wird.
>>> max("wer gewinnt wohl")
'w'
>>> min("zeichenkette")
'c'
13.1.7 Die Position eines Elements in der Sequenz – s.index(x, [i, j]) 

Mit index ermitteln Sie die Position eines Elements in einer Sequenz:
>>> ziffern = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> ziffern.index(3)
2
>>> s = "Hallo Welt"
>>> s.index("l")
2
Um die Suche auf einen Teilbereich der Sequenz einzuschränken, dienen die Parameter i und j, wobei j den ersten Index der gewünschten Teilfolge und i den ersten Index hinter der gewünschten Teilfolge angibt:
>>> folge = [0, 11, 222, 3333, 44444, 3333, 222, 11, 0]
>>> folge.index(222)
2
>>> folge.index(222, 3)
6
>>> folge.index(222, -5)
6
>>> "Hallo Welt".index("l", 5, 100)
8
Wie bei der Indizierung von Elementen der Sequenz werden negative Werte für i und j vom Ende der Sequenz aus gezählt. Im Beispiel oben wurde also mit folge. index(222, -5) in der Teilsequenz [44444, 3333, 222, 11, 0] gesucht, die beim fünften Element von hinten beginnt.
Ist das Element x nicht in s oder in der angegebenen Teilfolge enthalten, führt index zu einem ValueError:
>>> s = [2.5, 2.6, 2.7, 2.8]
>>> s.index(2.4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 2.4 is not in list
13.1.8 Anzahl der Vorkommen eines Elements der Sequenz – s.count(x) 

Sie können mit count ermitteln, wie oft ein bestimmtes Element x in einer Sequenz enthalten ist:
>>> s = [1, 2, 2, 3, 2]
>>> s.count(2)
3
>>> "Hallo Welt".count("l")
3
Der nächste Abschnitt beschäftigt sich mit Operationen, die nur für mutable Sequenzen verfügbar sind.