Sequentielle Datentypen

Einführung

Länge einer
							 sequentiellen Struktur Ein sequentieller Datentyp (oder Sequenztyp) ist ein Datentyp, der eine Folge von gleichartigen oder verschiedenen Elementen beinhaltet. Die Elemente eines sequentiellen Datentyps haben eine definierte Reihenfolge und dadurch kann man über Indices auf sie zugreifen.
Python stellt die folgenden Datentypen zur Verfügung:

Die im Folgenden besprochenen Operationen gelten für alle sequentiellen Datentypen.

Indizierung

Betrachten wir den String "Hello World":

Aufbau eines Strings

Man sieht, dass die Zeichen eines Strings von links nach rechts mit 0 beginnend nummeriert sind. Von hinten (rechts) beginnt man mit -1 zu zählen. Jedes Zeichen eines Strings kann so eindeutig angesprochen werden, sie können mit eckigen Klammern indizieren, wie man im folgenden Beispiel sehen kann:

>>> txt = "Hello World"
>>> txt[0]
'H'
>>> txt[4]
'o'
Statt von vorne kann man die Indizes auch von hinten bestimmen:
  >>> txt[-1]
  'd'
  >>> txt[-5]
  'W'
Dies funktioniert genauso für Listen und Tupel, aber zunächst müssen wir uns noch anschauen, wie Listen und Tupel in Python überhaupt aussehen:
Listen können beliebige Python-Objekte enthalten. Im folgenden Beispiel enthält "colours" 3 Strings und die Liste a enthält 4 Objekte, und zwar die Strings "Swen" und "Basel", die Ganzzahl 45 und die Fließkommazahl 3.54. Greift man nun analog zu dem Vorgehen bei Strings auf ein Listenelement mit einem Index zu, erhält man das jeweilige Element. So liefert colours[0] im folgenden Beispiel den String 'red' als Ergebnis.
  >>> colours = ['red', 'green', 'blue']
  >>> colours[0]
  'red'
  >>> colours
  ['red', 'green', 'blue']
  >>>
  >>>
  >>> a = ["Swen", 45, 3.54, "Basel"]
  >>> a[3]
  'Basel'
  >>> 

Beispiele

Listen werden von eckigen Klammern umgeben und mit Kommas getrennt. Die folgende Tabelle zeigt ein paar Beispiele:

Listen Beschreibung
[] Eine leere Liste
[1, 1, 2, 3, 5, 8] Eine Liste mit ganzen Zahlen
[42, "What's the question?", 3.1415] Eine Liste mit gemischten Datentypen
["Stuttgart", "Freiburg", "München", "Nürnberg", "Würzburg", "Ulm", "Friedrichshafen", Zürich", "Wien"] Eine Liste von Strings
[["London", "England", 7556900], ["Paris", "France",2193031], ["Bern", "Switzerland", 123466]] Eine verschachtelte Liste
["Oberste Ebene", ["Ein Level runter", ["noch tiefer", ["und tiefer", 42]]]] Eine tief verschachtelte Liste

Unterlisten

Listen können auch andere Listen als Elemente enthalten:

>>> pers = [["Marc","Mayer"],["Hauptstr. 17", "12345","Musterstadt"],"07876/7876"]
>>> name = pers[0]
>>> name[1]
'Mayer'
>>> adresse = pers[1]
>>> adresse[1]
'12345'
>>> pers[2]
'07876/7876'
>>> strasse = pers[1][0]
>>> strasse
'Hauptstr. 17'
>>>

Tupel

Man kann sich ein Tupel als eine unveränderliche Liste vorstellen. Sprich, wenn es einmal erstellt wurde, kann sein Inhalt nicht mehr verändert werden. Das bedeutet, dass weder Elemente hinzugefügt noch Elemente gelöscht werden können. Tupel werden auf die gleiche Art definiert wie Listen, nur dass statt der eckigen Klammern nun runde Klammern verwendet werden.

Was sind die Vorteile von Tupeln?

  • Tupel sind performanter als Listen.
  • Wenn bekannt ist, dass Daten nicht geändert werden müssen, sollten Tupel verwendet werden, um ungewollte Änderungen zu vermeiden.
  • Der wichtigste Vorteil liegt aber darin, dass Tupel auch als Schlüssel in Dictionaries verwendet werden können, da Schlüssel nur Objekte von unveränderlichen Datentypen sein können. Listen können dazu nicht verwendet werden.

    Im Folgenden bringen wir ein kurzes Beispiel zur Definition und zum Zugriff eines Tupels. Weiterhin können wir sehen, dass ein Fehler produziert wird, wenn wir versuchen das Tupel zu ändern.
    >>> t = ("tuples", "are", "immutable")
    >>> t[0]
    'tuples'
    >>> t[0]="assignments to elements are not possible"
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'tuple' object does not support item assignment
    

    Ausschneiden / Slicing

    Man kann auch Teile eines sequentiellen Datentyps ausschneiden. Im Falle eines Strings erhält man dann einen Teilstring oder bei Listen wieder eine Liste. Im Englischen wird dieses Ausschneiden als "slicing" bezeichnet. In der Überschrift zu diesem Kapitel benutzen wir sowohl den Begriff "Slicing" als auch "Ausschneiden", da wir uns nicht für die deutsche Übersetzung eindeutig entscheiden wollten. Der Begriff "Slicing" wird in der deutschen Python-Literatur allzu häufig benutzt. Deshalb werden wir die beiden Begriffe im Folgenden synonym benutzen. Wie bei der Indizierung benutzt der Slicing-Operator eckige Klammern, aber nun werden statt einem Wert mindestens zwei Werte erwartet: Anfangswert und Endwert.
    Man versteht dies am besten an einem Beispiel:

    >>> txt = "Hello World"
    >>> txt[1:5]
    'ello'
    >>> txt[0:5]
    'Hello'
    
    Lässt man den Anfangswert weg (z.B. [:5] ), beginnt das Ausschneiden am Anfang des Strings (oder der Liste). Analog kann man auch den Endwert weglassen, um alles bis zum Ende zu übernehmen, also zum Beispiel [6:] ).
    Lässt man sowohl den Anfangs- als auch den Endwert weg, erhält man den ganzen String (oder entsprechend die ganze Liste oder Tupel) zurück:
    >>> txt[0:-6]
    'Hello'
    >>> txt[:5]
    'Hello'
    >>> txt[6:]
    'World'
    >>> txt[:]
    'Hello World'
    
    Das folgende Beispiel zeigt, wie sich dies bei Listen auswirkt:
    >>> colours = ['red', 'green', 'blue']
    >>> colours[1:3]
    ['green', 'blue']
    >>> colours[2:]
    ['blue']
    >>> colours[:2]
    ['red', 'green']
    >>> 
    >>> colours[-1]
    'blue'
    

    Der obige Slicing-Operator funktioniert auch mit drei Argumenten. Das dritte Argument gibt dann an, das wievielte Argument jedes mal genommen werden soll, d.h. s[begin, end, step].
    Ausgegeben werden dann die folgenden Elemente von s:
    s[begin], s[begin + 1 * step], ... s[begin + i * step] solange (begin + i * step) < end ist.
    txt[::3] gibt jeden dritten Buchstaben eines Strings aus.
    Beispiel:
    >>> txt = "Python ist ganz toll"
    >>> txt[2:15:3]
    'tnsgz'
    >>> txt[::3]
    'Ph ta l'
    
    Der Schrittweite, also der Wert nach dem zweiten Doppelpunkt, kann auch negativ sein: In diesem Fall werden die Objekte in umgekehrter Reihenfolge in der entsprechenden Schrittweite ausgegeben. Manche suchen nach einer Funktion in Python, um einen String umzukehren. Python benötigt keine solche Funktion, da man die Umkehrung eines Strings mit der Schrittweite -1 sehr einfach realisieren kann:
    >>> s = "Hamburg"
    >>> s[::-1]
    'grubmaH'
    >>> s = "Frankfurt"
    >>> s[::-2]
    'tukaF'
    >>> 
    >>> staedte = ["Berlin", "Frankfurt", "Stuttgart", "Zürich", "Basel"]
    >>> staedte[::-1]
    ['Basel', 'Zürich', 'Stuttgart', 'Frankfurt', 'Berlin']
    

    Länge

    Länge einer
							 sequentiellen Struktur Die Länge eines sequentiellen Datentyps entspricht der Anzahl seiner Elemente und wird mit der Funktion len() bestimmt.

    >>> txt = "Hello World"
    >>> len(txt)
    11
    >>> 
    
    Funktioniert ebenso bei Listen:
    >>> a = ["Swen", 45, 3.54, "Basel"]
    >>> len(a)
    4
    

    Verkettung von Sequenzen

    Eine sinnvolle und häufig benötigte Operation auf Sequenzen ist die Verkettung (engl. concatenation). Als Operatorzeichen für die Verkettung dient das +-Zeichen. Im folgenden Beispiel werden zwei Strings zu einem verkettet:
    >>> firstname = "Homer"
    >>> surname = "Simpson"
    >>> name = firstname + " " + surname
    >>> print(name)
    Homer Simpson
    >>>  
    
    Für Listen geht dies genauso einfach, wie das folgende selbsterklärende Beispiel zeigt:
    >>> colours1 = ["red", "green","blue"]
    >>> colours2 = ["black", "white"]
    >>> colours = colours1 + colours2
    >>> print(colours)
    ['red', 'green', 'blue', 'black', 'white']
    
    Eine sehr gebräuchliche Methode zur Verkettung bietet der +=-Operator, der in vielen anderen Programmiersprachen vor allem bei numerischen Zuweisungen verwendet wird. Der +=-Operator wird als eine abgekürzte Schreibweise benutzt.

    So steht
    s += t
    
    für die Anweisung:
    s = s + t
    

    Prüfung, ob Element in Sequenz enthalten

    Bei Sequenzen kann man auch prüfen, ob (oder ob nicht) ein Element in einer Sequenz vorhanden ist. Dafür gibt es die Operatoren "in" und "not in".
    Die Arbeitsweise erkennt man im folgenden Protokoll einer interaktiven Sitzung:

    >>> abc = ["a","b","c","d","e"]
    >>> "a" in abc
    True
    >>> "a" not in abc
    False
    >>> "e" not in abc
    False
    >>> "f" not in abc
    True
    >>> str = "Python ist toll!"
    >>> "y" in str
    True
    >>> "x" in str
    False
    >>> 
    

    Wiederholungen

    Für Sequenzen ist in Python auch ein Produkt definiert. Das Produkt einer Sequenz s mit einem Integer-Wert n (s * n bzw. n * s) ist als n-malige Konkatenation von s mit sich selbst definiert.

    >>> 3 * "xyz-"
    'xyz-xyz-xyz-'
    >>> "xyz-" * 3
    'xyz-xyz-xyz-'
    >>> 3 * ["a","b","c"]
    ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
    
    s *= n ist (wie üblich) die Kurzform für s = s * n.

    Die Tücken der Wiederholungen

    In den vorigen Beispielen haben wir den Wiederholungsoperator nur auf Strings und flache Listen angewendet. Wir können ihn aber auch auf verschachtelte Listen anwenden:
     
    >>> x = ["a","b","c"]
    >>> y = [x] * 4
    >>> y
    [['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]
    >>> y[0][0] = "p"
    >>> y
    [['p', 'b', 'c'], ['p', 'b', 'c'], ['p', 'b', 'c'], ['p', 'b', 'c']]
    >>> 
    
    Wiederholungen mit Referenzen

    Das Ergebnis ist für Anfänger der Python-Programmierung sehr erstaunlich. Wir haben dem ersten Element der ersten Unterliste (also y[0][0]) einen neuen Wert zugewiesen und gleichzeitig haben wir automatisch das jeweilige erste Element aller anderen Unterlisten auch verändert, also y[1][0], y[2][0], y[3][0]
    Der Grund für dieses scheinbar merkwürdige Verhalten liegt darin, dass der Wiederholungsoperator "* 4" vier Referenzen auf die Liste x anlegt.