8.5 Sequenzielle Datentypen 

Unter sequenziellen Datentypen wird eine Klasse von Datentypen zusammengefasst, die Folgen von gleichartigen oder verschiedenen Elementen verwalten können. Die in sequenziellen Datentypen gespeicherten Elemente haben eine definierte Reihenfolge, und man kann über eindeutige Indizes auf sie zugreifen.
Python stellt die folgenden fünf sequenziellen Typen zu Verfügung: str, unicode, list und tuple.
Mithilfe der ersten beiden sequenziellen Datentypen, str und unicode wird in Python die Arbeit mit Zeichenketten, also Folgen von Buchstaben, ermöglicht, wobei je nach Anwendungsfall einer von ihnen besser geeignet ist. Instanzen des Typs str speichern Folgen von Bytes und eignen sich daher besonders für binäre Datenströme, aber auch für Zeichenketten, die nur aus ASCII-Zeichen bestehen. Der Datentyp unicode ist für die Speicherung von Text-Strings konzipiert und speichert Folgen von Zeichen in einem speziellen Unicode-Format, das auch die komfortable Verwaltung von speziellen Sonderzeichen wie den deutschen Umlauten oder dem Eurozeichen ermöglicht.
Beide Datentypen sind immutable, 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 mutable, tuple ein immutable 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 str-Instanzen einführen und erst in den folgenden Abschnitten Besonderheiten bezüglich der einzelnen Datentypen aufzeigen.
Für alle sequenziellen Datentypen sind folgende Operationen definiert (s und t sind hierbei Instanzen desselben sequenziellen Datentyps; i, j, k und n sind Ganzzahlen, x ist eine Referenz auf eine beliebige Instanz):
| Notation | Beschreibung |
|
x in s
|
Prüft, ob x in s enthalten ist. Das Ergebnis ist eine bool-Instanz. |
|
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. |
|
s + t
|
Das Ergebnis ist eine neue Sequenz, die die Verkettung von s und t enthält. |
|
s += t
|
Erzeugt die Verkettung von s und t und weist sie s zu. |
|
s * n oder n * s |
Liefert eine neue Sequenz, die die Verkettung von n Kopien von s enthält. |
|
s *= n |
Erzeugt das Produkt s * n und weist es s zu. |
|
s[i]
|
Liefert das i-te Element von s. |
|
s[i:j]
|
Liefert den Ausschnitt aus s von i bis j. |
|
s[i:j:k]
|
Liefert den Ausschnitt aus s von i bis j, wobei nur jedes k-te Element beachtet wird. |
|
len(s)
|
Gibt eine Ganzzahl zurück, die die Anzahl der Elemente von s angibt. |
|
min(s)
|
Liefert das kleinste Element von s, sofern eine Ordnungsrelation für die Elemente definiert ist. |
|
max(s)
|
Liefert das größte Element von s, sofern eine Ordnungsrelation für die Elemente definiert ist. |
Wie bereits bekannt ist, lässt sich ein neuer String erzeugen, indem man seinen Inhalt in doppelte Hochkommata schreibt:
>>> s = "Dies ist unser Teststring"
Ist ein Element vorhanden?
Mithilfe von in lässt sich ermitteln, ob ein bestimmtes Element in einer Sequenz enthalten ist. Da die Elemente eines Strings Buchstaben 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. Buchstaben kann man in Python durch Strings der Länge eins abbilden:
>>> s = "Dies ist unser Teststring" >>> "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...
Um das Gegenteil – also ob ein Element nicht in einer Sequenz enthalten ist – zu prüfen, dient der not in-Operator. Seine Verwendung entspricht der des in-Operators, mit dem einzigen Unterschied, dass er das negierte Ergebnis 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 vollkommen 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. x not in s liest sich im Gegensatz zu not x in s genau wie ein englischer Satz, während die andere Form unnötig kompliziert zu lesen ist. [Zusätzlich muss man 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. ]
Verkettung von Sequenzen
Es kommt häufig vor, dass man mehrere Sequenzen aneinanderhängen möchte, um mit dem Ergebnis weiterzuarbeiten. Beispielsweise könnte man den Vor- und den Nachnamen eines Benutzers zu seinem gesamten Namen zusammenfügen, um ihn dann persönlich zu begrüßen. Für solche Zwecke dient der +-Operator, der aus zwei Sequenzen eine neue erzeugt, indem er die beiden 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" >>> s += "lautsprecher" >>> s 'Musiklautsprecher'
Wiederholung von Sequenzen
Man kann in Python 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'
Genau wie bei der Verkettung gibt es auch hier einen Operator für die erweiterte Zuweisung: *=. Da seine Verwendung analog zu += erfolgt, wurde auf ein weiteres platzhungriges Beispiel verzichtet.
Zugriff auf bestimmte Elemente einer Sequenz
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, wenig sinnvoll –, kann man jedem Element der Sequenz eine ganze Zahl, den sogenannten 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 kann man auf ein bestimmtes Element der Sequenz zugreifen, indem man den entsprechenden Index in die eckigen Klammern schreibt:
>>> alphabet = "abcdefghijklmnopqrstuvwxyz" >>> alphabet[9] 'j' >>> alphabet[1] 'b'
Um komfortabel 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:
>>> name = "Python" >>> name[-2] 'o'
Versucht man, 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 erreicht man dadurch, dass man den Anfang und das Ende der gewünschten Teilfolge durch einen Doppelpunkt getrennt in die eckigen Klammern schreibt. 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 = "schrottschrottWICHTIGschrottschrott" >>> s[14] 'W' >>> s[21] 's' >>> s[14:21] 'WICHTIG'
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'
Aus Bequemlichkeitsgründen können die Indizes 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 verzichtet man auf den Endindex, werden alle Buchstaben bis zum Ende kopiert. Möchten wir zum Beispiel die ersten fünf Buchstaben eines Strings oder alle ab dem fünften ermitteln, geht das folgendermaßen:
>>> s = "abcdefghijklmnopqrstuvwxyz" >>> s[:5] 'abcde' >>> s[5:] 'fghijklmnopqrstuvwxyz'
Wenn man beide Indizes ausspart (s[:]), lässt sich 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 = "Kopier mich!"
>>> s2 = s1
>>> s1 == s2
True
>>> s1 is s2
TrueWie 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 von "Kopier mich!" im Speicher erzeugt wird. Dies zeigt sich beim Identitätsvergleich mit is:
>>> s1 = "Kopier mich!"
>>> s2 = s1[:]
>>> s1 == s2
True
>>> s1 is s2
FalseSlicing 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) lässt sich 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 Element (Achtung: Die Zählweise beginnt bei 0) 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 vorherigen 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 sehr elegant 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, zu kleine durch den minimal möglichen Index ersetzt. Liegen beide Indizes außerhalb des gültigen Bereichs oder ist der Startindex bei positiver Schrittweise 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] ''
Länge einer Sequenz
Als Länge einer Sequenz ist in Python die Anzahl ihrer Elemente definiert. Sie ist eine ganze Zahl größer oder gleich null und lässt sich mit der Built-in-Function len ermitteln:
>>> string = "Wie lang bin ich wohl?" >>> len(string) 22
Das kleinste und das größte Element einer Sequenz
Eine sehr häufige Aufgabe innerhalb eines Programms besteht darin, das kleinste beziehungsweise größte Element einer Sequenz zu ermitteln. Aus diesem Grund existieren in Python die Funktionen min und max, wobei min das kleinste und max das größte Element zurückgibt. Allerdings machen diese beiden Funktionen nur dann Sinn, wenn eine Ordnungsrelation für die Elemente der Sequenz existiert (in Abschnitt 8.3.4 über komplexe Zahlen wird zum Beispiel ein Datentyp ohne Ordnungsrelation beschrieben). Für Buchstaben wird ihre Position im Alphabet als Ordnungsrelation benutzt, solange es sich nur um Großbuchstaben oder nur um Kleinbuchstaben handelt. Beim Vergleichen von Groß- und Kleinbuchstaben untereinander gelten Kleinbuchstaben immer als größer [Falls Sie sich über dieses merkwürdige Verhalten wundern: Die Reihenfolge im Alphabet beschreibt nur einen Teilaspekt der Ordnungsrelation für einzelne Zeichen. Sonderzeichen wie beispielsweise das Leerzeichen lassen sich damit nicht sinnvoll einordnen. Sie werden im Abschnitt über Strings die Hintergründe hierzu kennenlernen. ] – "a" ist also kleiner als "z" und größer als "A":
>>> max("wer gewinnt wohl") 'w' >>> min("zeichenkette") 'c'
8.5.1 Listen – list 

In diesem Abschnitt werden Sie den ersten veränderbaren (mutable) Datentyp, die Liste, kennenlernen. Anders als bei dem sequenziellen Datentyp str, der nur gleichartige Elemente, die Buchstaben, speichern kann, sind Listen für die Verwaltung beliebiger Instanzen auch unterschiedlicher Datentypen geeignet. Eine Liste kann also durchaus Zahlen, Strings oder auch weitere Listen als Elemente enthalten, wodurch sie sehr flexibel anwendbar ist.
Eine neue Liste lässt sich dadurch erzeugen, dass man eine Aufzählung ihrer Elemente in eckige Klammern [] schreibt:
>>> l = [1, 0.5, "String", 2]Die Liste l enthält nun zwei Ganzzahlen, eine Gleitkommazahl und einen String.
Da es sich bei dem Listentyp, der innerhalb von Python den Namen list hat, um einen sequenziellen Datentyp handelt, können alle im letzten Abschnitt beschriebenen Methoden und Verfahren auf ihn angewandt werden.
Allerdings kann sich der Inhalt einer Liste auch nach ihrer Erzeugung ändern, weshalb eine Reihe weiterer Operatoren und Methoden für sie verfügbar sind:
| Operator | Wirkung |
|
s[i] = x |
Das Element von s mit dem Index i wird durch x ersetzt. |
|
s[i:j] = t |
Der Teil s[i:j] wird durch t ersetzt. Dabei muss t iterierbar sein. |
|
s[i:j:k] = t |
Die Elemente von s[i:j:k] werden durch die von t ersetzt. |
|
del s[i] |
Das i-te Element von s wird entfernt. |
|
del s[i:j] |
Der Teil s[i:j] wird aus s entfernt. Das ist äquivalent zu s[i:j] = []. |
|
del s[i:j:k] |
Die Elemente der Teilfolge s[i:j:k] werden aus s entfernt. |
Wir werden diese Operatoren der Reihe nach mit kleinen Beispielen erklären.
Verändern eines Wertes innerhalb der Liste
Man kann Elemente einer Liste durch andere ersetzen, wenn man ihren Index kennt:
>>> s = [1, 2, 3, 4, 5, 6, 7] >>> s[3] = 1337 >>> s [1, 2, 3, 1337, 5, 6, 7]
Diese Methode eignet sich allerdings nicht, um mehr Elemente in die Liste einzufügen. Es können nur bereits bestehende Elemente ersetzt werden, und die Länge der Liste bleibt unverändert.
Ersetzen von Teillisten und Einfügen neuer Elemente
Es ist möglich, eine ganze Teilliste durch andere Elemente zu ersetzen. Dazu schreibt man den zu ersetzenden Teil der Liste wie beim Slicing auf, wobei er aber auf der linken Seite einer Zuweisung stehen muss:
>>> einkaufen = ["Brot", "Eier", "Milch", "Fisch", "Mehl"] >>> einkaufen[1:3] = ["Wasser", "Wurst"] >>> einkaufen ['Brot', 'Wasser', 'Wurst', 'Fisch', 'Mehl']
Die Liste, die eingefügt werden soll, kann auch mehr oder weniger Elemente als der zu ersetzende Teil haben und sogar ganz leer sein.
Man kann wie beim Slicing auch eine Schrittweite angeben, um beispielsweise nur jedes dritte Element der Teilsequenz zu ersetzen. Im nachstehenden Beispiel wird jedes dritte Element der Teilsequenz s[2:11] durch das entsprechende Element aus ["A", "B", "C"] ersetzt:
>>> s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> s[2:9:3] = ["A", "B", "C"]
>>> s
[0, 1, 'A', 3, 4, 'B', 6, 7, 'C', 9, 10]Wird eine Schrittweite angegeben, muss die Sequenz auf der rechten Seite der Zuweisung genauso viele Elemente wie die Teilsequenz auf der linken Seite haben. Ist das nicht der Fall, wird ein ValueError erzeugt.
Elemente und Teillisten löschen
Um einen einzelnen Wert aus einer Liste zu entfernen, dient der del-Operator:
>>> s = [26, 7, 1987] >>> del s[0] >>> s [7, 1987]
Auf diese Weise lassen sich auch ganze Teillisten entfernen:
>>> s = [9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> del s[3:6]
>>> s
[9, 8, 7, 3, 2, 1]Für das Entfernen von Teilen einer Liste wird auch die Schrittfolge der Slicing-Notation unterstützt. Im folgenden Beispiel werden damit alle Elemente mit geradem Index entfernt (Achtung: "a" hat den Index 0):
>>> s = ["a","b","c","d","e","f","g","h","i","j"] >>> del s[::2] >>> s ['b', 'd', 'f', 'h', 'j']
Nachdem nun die Operatoren für Listen behandelt worden sind, wenden wir uns den Methoden einer Liste zu. In der Tabelle sind s und t Listen, i, j und k sind Ganzzahlen, und ist x eine beliebige Instanz:
| Methode | Wirkung |
|
s.append(x) |
Hängt x ans Ende von s an. |
|
s.extend(t) |
Hängt alle Elemente von t ans Ende von s an. |
|
s.count(x) |
Gibt an, wie oft das Element x in s vorkommt. |
|
s.index(x[, i[, j]]) |
Gibt den Index k des ersten Vorkommens von x im Bereich i <= k < j zurück. |
|
s.insert(i, x) |
Fügt x an der Stelle i in s ein. Anschließend hat s[i] den Wert von x, wobei alle folgenden Elemente um eine Stelle nach hinten aufrücken. |
|
s.pop([i]) |
Gibt das i-te Element von s zurück und entfernt es aus s. Ist i nicht angegeben, wird das letzte Element genommen. |
|
s.remove(x) |
Entfernt das erste Vorkommen von x aus der Sequenz s. |
|
s.reverse() |
Kehrt die Reihenfolge der Elemente in s um. |
|
s.sort([cmp[, key[, reverse]]) |
Sortiert s. |
s.append(x)
Mit append kann man eine Liste am Ende um ein weiteres Element erweitern:
>>> s = ["Nach mir soll noch ein String stehen"] >>> s.append("Hier ist er") >>> s ['Nach mir soll noch ein String stehen', 'Hier ist er']
s.extend(t)
Um an eine Liste mehrere Elemente anzuhängen, dient die Methode extend, die ein iterierbares Objekt – beispielsweise eine andere Liste – als Parameter t erwartet. Im Ergebnis werden alle Elemente von t an die Liste s angehängt:
>>> s = [1, 2, 3] >>> s.extend([4, 5, 6]) >>> s [1, 2, 3, 4, 5, 6]
s.count(x)
Man kann mit count ermitteln, wie oft ein bestimmtes Element x in einer Liste enthalten ist:
>>> s = [1, 2, 2, 3, 2] >>> s.count(2) 3
s.index(x[, i[, j]])
Mit index kann man die Position eines Elements in einer Liste ermitteln:
>>> ziffern = [1, 2, 3, 4, 5, 6, 7, 8, 9] >>> ziffern.index(3) 2
Um die Suche auf einen Teilbereich der Liste einzuschränken, dienen die Parameter i und k, wobei i den ersten Index der gewünschten Teilfolge und k den ersten Index hinter der gewünschten Teilfolge angibt:
>>> [1, 22, 333, 4444, 333, 22, 1].index(1, 3, 7) 6
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 "<pyshell#21>", line 1, in <module>
s.index(2.4)
ValueError: list.index(x): x not in lists.insert(i, x)
Mit insert kann man an beliebiger Stelle ein neues Element in eine Liste einfügen. Der erste Parameter i gibt den gewünschten Index des neuen Elements, der zweite, x, das Element selbst an:
>>> erst_mit_loch = [1, 2, 3, 5, 6, 7, 8] >>> erst_mit_loch.insert(3, 4) >>> erst_mit_loch [1, 2, 3, 4, 5, 6, 7, 8]
Ist der Index i zu klein, wird x am Anfang von s eingefügt, ist er zu groß, wird er wie bei append am Ende angehängt.
s.pop([i])
Das Gegenstück zu insert ist pop. Mit dieser Methode kann man ein beliebiges Element anhand seines Index aus einer Liste entfernen. Ist der optionale Parameter nicht angegeben, so wird das letzte Element der Liste entfernt. Das entfernte Element wird von pop zurückgegeben:
>>> s = ["H", "a", "l", "l", "o"] >>> s.pop() 'o' >>> s.pop(0) 'H' >>> s ['a', 'l', 'l']
Wird versucht, einen ungültigen Index zu übergeben oder ein Element aus einer leeren Liste zu entfernen, wird ein IndexError erzeugt.
s.remove(x)
Möchte man ein Element mit einem bestimmten Wert aus einer Liste entfernen, egal welchen Index es hat, kann man die Methode remove bemühen. Sie entfernt das erste Element der Liste, das den gleichen Wert wie x hat.
>>> s = ["H", "u", "h", "u"]
>>> s.remove("u")
>>> s
['H', 'h', 'u']Der Versuch, ein nicht vorhandenes Element zu entfernen, führt zu einem ValueError.
s.reverse()
Mit reverse kann man die Reihenfolge der Elemente einer Liste umkehren:
>>> s = [1, 2, 3] >>> s.reverse() >>> s [3, 2, 1]
Im Unterschied zu der Slice-Notation s[::-1] geschieht die Umkehrung »in place«. Es wird also keine neue list-Instanz erzeugt, sondern die alte verändert. Da dies weniger Rechenzeit und Speicher kostet, ist reverse der Slice-Notation vorzuziehen, wenn man nicht unbedingt eine neue Liste braucht.
s.sort([cmp[, key[, reverse]])
Die komplexeste Methode des list-Datentyps ist sort, mit der eine Liste nach bestimmten Kriterien sortiert werden kann. Ruft man die Methode ohne Parameter auf, benutzt Python die normalen Vergleichsoperatoren zum Sortieren:
>>> l = [4, 2, 7, 3, 6, 1, 9, 5, 8] >>> l.sort() >>> l [1, 2, 3, 4, 5, 6, 7, 8, 9]
Enthält eine Liste Elemente, für die keine Ordnungsrelation definiert ist, wie zum Beispiel complex, führt der Aufruf von sort ohne Parameter zu einem TypeError:
>>> lst = [5 + 13j, 1 + 4j, 6 + 2j]
>>> lst.sort()
Traceback (most recent call last):
File "<pyshell#18>", line 1, in <module>
lst.sort()
TypeError: no ordering relation is defined for complex numbersAngenommen, wir wollten eine Liste komplexer Zahlen nach ihrem Imaginärteil sortieren, könnten wir den optionalen Parameter cmp benutzen. Die Methode erwartet im Parameter cmp eine Referenz auf eine Funktion, die ihrerseits zwei Parameter erwartet und diese vergleicht. Ist der Wert des ersten Parameters kleiner als der des zweiten, soll der Rückgabewert der übergebenen Funktion negativ sein; ist er größer, muss cmp eine positive Zahl zurückgeben. Bei gleich einzuordnenden Werten soll die übergebene Funktion 0 zurückgeben. Wir haben bis jetzt noch nicht besprochen, wie eigene Funktionen definiert werden, aber das behandelte Beispiel sollte trotzdem verständlich sein. Wenn Sie genau nachlesen möchten, was es mit Funktionsdefinitionen auf sich hat, können Sie sich im Kapitel 10 informieren.
Der folgende Code-Ausschnitt definiert eine Funktion mit dem Namen vergleiche_complex, die zwei complex-Instanzen hinsichtlich ihres Imaginärteils vergleicht:
>>> def vergleiche_complex(a, b): ... return a.imag - b.imag
Die Funktion erwartet zwei Parameter, a und b, und nutzt ihre Differenz, um die Imaginärteile zu vergleichen. Wenn a.imag größer als b.imag ist, wird ihre Differenz positiv, sind sie gleich, ergibt a.imag - b.imag den Wert 0. Ist b.imag der größere der beiden Werte, wird eine negative Zahl zurückgegeben. Mit der return-Anweisung wird der Rückgabewert an die aufrufende Ebene übergeben. Mithilfe dieser Funktion können wir nun die Liste aus complex-Instanzen sortieren:
>>> lst = [5 + 13j, 1 + 4j, 6 + 2j] >>> lst.sort(vergleiche_complex) >>> lst [(6+2j), (1+4j), (5+13j)]
Wie Sie an der abschließenden Ausgabe sehen können, wurde die Liste korrekt sortiert.
Eine weitere Möglichkeit, die Sortierung anzupassen, bietet der Parameter key, der ebenfalls eine Funktionsreferenz erwartet. Die übergebende Funktion wird vor jedem Vergleich für beide Operanden aufgerufen und sollte deshalb einen Parameter erwarten. Im Ergebnis werden dann nicht die Operanden direkt verglichen, sondern stattdessen die entsprechenden Rückgabewerte der übergebenen Funktion.
Zur Veranschaulichung werden wir das letzte Beispiel unter Verwendung des Parameters key implementieren. Die benötigte Funktion muss den Imaginärteil einer übergebenen complex-Instanz zurückgeben:
>>> def imag_teil(c): ... return c.imag
Es kommt sehr selten vor, dass man sowohl den cmp- als auch den key-Parameter übergibt, da die Operationen der key-Funktion ebenso gut innerhalb der cmp-Funktion erledigt werden können. Deshalb bietet sich eine Übergabe als Schlüsselwortparameter an:
>>> lst = [5 + 13j, 1 + 4j, 6 + 2j] >>> lst.sort(key=imag_teil) >>> lst [(6+2j), (1+4j), (5+13j)]
Das Ergebnis deckt sich mit unseren Erwartungen.
Der letzte Parameter, reverse, erwartet für die Übergabe einen booleschen Wert, der angibt, ob die Reihenfolge der Sortierung umgekehrt werden soll:
>>> l = [4, 2, 7, 3, 6, 1, 9, 5, 8] >>> l.sort(reverse=True) [9, 8, 7, 6, 5, 4, 3, 2, 1]
Stabile Sortierverfahren
Eine wichtige Eigenschaft von sort ist, dass es sich um eine stabile Sortierung handelt. Stabile Sortierverfahren zeichnen sich dadurch aus, dass sie beim Sortieren die relative Position gleichwertiger Elemente nicht vertauschen. Stellen Sie sich einmal vor, Sie hätten folgende Namensliste:
| Vorname | Nachname |
|
Natalie |
Schmidt |
|
Mathias |
Schwarz |
|
Florian |
Kroll |
|
Ricarda |
Schmidt |
|
Helmut |
Schmidt |
|
Peter |
Kaiser |
Nun ist es Ihre Aufgabe, diese Liste nach den Nachnamen zu sortieren. Gruppen mit gleichem Nachnamen sollen nach den jeweiligen Vornamen sortiert werden. Um dieses Problem zu lösen, können Sie die Liste im ersten Schritt nach den Vornamen sortieren, was zu folgender Anordnung führt:
| Vorname | Nachname |
|
Florian |
Kroll |
|
Helmut |
Schmidt |
|
Mathias |
Schwarz |
|
Natalie |
Schmidt |
|
Peter |
Kaiser |
|
Ricarda |
Schmidt |
Im Resultat interessieren uns jetzt nur die Positionen der drei Personen, deren Nachname »Schmidt« ist. Würde man einfach alle anderen Namen streichen, wären die Schmidts richtig sortiert, weil ihre relative Position durch den ersten Sortierlauf korrekt hergestellt wurde. Nun kommt die Stabilität der sort-Methode zum Tragen, weil dadurch bei einem erneuten Sortierdurchgang nach den Nachnamen diese relative Ordnung nicht zerstört wird. Das Ergebnis sähe am Ende so aus:
| Vorname | Nachname |
|
Peter |
Kaiser |
|
Florian |
Kroll |
|
Helmut |
Schmidt |
|
Natalie |
Schmidt |
|
Ricarda |
Schmidt |
|
Mathias |
Schwarz |
Wäre sort nicht stabil, so gäbe es keine Garantie dafür, dass Helmut vor Natalie und Ricarda eingeordnet wird.
Wie Sie sehen, ist die sort-Methode extrem flexibel und mächtig. Bei Ihrer Arbeit mit Python werden Sie höchstwahrscheinlich niemals etwas anderes zum Sortieren Ihrer Daten verwenden.
Weitere Eigenschaften von Listen
Im Zusammenhang mit Pythons list-Datentyp ergeben sich ein paar Besonderheiten, die nicht unmittelbar ersichtlich sind.
Zum einen ist list ein veränderbarer Datentyp, und deshalb betreffen Änderungen an einer list-Instanz immer alle Referenzen, die auf sie verweisen. Betrachten wir einmal das folgende Beispiel, in dem der unveränderliche Datentyp str mit list verglichen wird:
>>> a = "Hallo "
>>> b = a
>>> b += "Welt"
>>> b
'Hallo Welt'
>>> a
'Hallo 'Dieses Beispiel erzeugt einfach eine str-Instanz mit dem Wert "Hallo " und lässt die beiden Referenzen a und b auf sie verweisen. Anschließend wird mit dem Operator += an den String, auf den b verweist, "Welt" angehängt. Wie die Ausgaben zeigen und wie wir es auch erwartet haben, wird eine neue Instanz mit dem Wert "Hallo Welt" erzeugt und b zugewiesen, a bleibt davon unberührt.
Übertragen wir das obige Beispiel auf Listen, ergibt sich ein wichtiger Unterschied:
>>> a = [1337] >>> b = a >>> b += [2674] >>> b [1337, 2674] >>> a [1337, 2674]
Strukturell gleicht der Code dem str-Beispiel, nur ist diesmal der verwendete Datentyp nicht str, sondern list. Der interessante Teil ist die Ausgabe am Ende, laut der a und b denselben Wert haben, obwohl die Operation nur auf b durchgeführt wurde. Tatsächlich verweisen a und b auf dieselbe Instanz, wovon man sich durch die Built-in Function id überzeugen kann:
>>> id(a) == id(b) True
Diese sogenannten Seiteneffekte [Seiteneffekte werden im Zusammenhang mit Funktionen in Abschnitt 10.2.4 eine wichtige Rolle spielen. ] sollte man bei der Arbeit mit Listen im Hinterkopf behalten. Wenn man sichergehen möchte, dass die Originalliste nicht verändert wird, kann man mithilfe von Slicing eine echte Kopie anlegen:
>>> a = [1337] >>> b = a[:] >>> b += [2674] >>> b [1337, 2674] >>> a [1337]
In diesem Beispiel wurde die von a referenzierte Liste kopiert und so vor indirekten Manipulationen über b geschützt. Man muss in solchen Fällen die Performance gegen den Schutz vor Seiteneffekten abwägen, da die Kopien der Listen im Speicher erzeugt werden müssen. Das kostet insbesondere bei langen Listen Rechenzeit und Speicherplatz und kann somit das Programm ausbremsen.
Im Zusammenhang mit Seiteneffekten sind auch die Elemente einer Liste interessant: Eine Liste speichert keine Instanzen an sich, sondern nur Referenzen auf sie. Das macht Listen einerseits flexibler und performanter, andererseits aber auch anfällig für Seiteneffekte. Schauen wir uns einmal das folgende, auf den ersten Blick merkwürdig anmutende Beispiel an:
>>> a = [[]] >>> a = 4 * a >>> a [[], [], [], []] >>> a[0].append(10) >>> a [[10], [10], [10], [10]]
Zu Beginn referenziert a eine Liste, in der eine weitere, leere Liste enthalten ist. Bei der anschließenden Multiplikation mit dem Faktor 4 wird die innere leere Liste nicht kopiert, sondern nur weitere drei Male referenziert. In der Ausgabe sehen wir also viermal dieselbe Liste. Wenn man das verstanden hat, ist es offensichtlich, warum die dem ersten Element von a angehängte 10 auch den anderen drei Listen hinzugefügt wird: Es handelt sich einfach um dieselbe Liste.
Es ist auch durchaus möglich, dass eine Liste sich selbst als Element enthält:
>>> a = [] >>> a.append(a)
Das Resultat ist eine unendlich tiefe Verschachtelung, da jede Liste wiederum sich selbst als Element enthält. Da nur Referenzen gespeichert werden müssen, verbraucht diese unendliche Verschachtelung nur sehr wenig Speicher und nicht, wie man zunächst vermuten könnte, unendlich viel. Trotzdem bergen solche Verschachtelungen die Gefahr von Endlosschleifen, wenn man die enthaltenen Daten verarbeiten möchte. Stellen Sie sich beispielsweise einmal vor, Sie wollten eine solche Liste auf dem Bildschirm ausgeben. Das würde zu unendlich vielen öffnenden und schließenden Klammern führen und somit den Computer lahmlegen. Trotzdem ist es möglich, solche Listen mit print auszugeben. Python überprüft selbstständig, ob eine Liste sich selbst enthält, und gibt dann anstelle von weiteren Verschachtelungen drei Punkte ... aus:
>>> a = [] >>> a.append(a) >>> a [[...]]
Bitte beachten Sie, dass die Schreibweise mit den drei Punkten kein gültiger Python-Code ist, um in sich selbst verschachtelte Listen zu erzeugen.
Wenn Sie selbst mit Listen arbeiten, die rekursiv sein könnten, sollten Sie Ihre Programme mit Abfragen ausrüsten, um Verschachtelungen von Listen mit sich selbst zu erkennen, damit das Programm bei der Verarbeitung nicht in einer endlosen Schleife stecken bleiben kann.
8.5.2 Unveränderliche Listen – tuple 

Der Datentyp list ist sehr flexibel und wird häufig gebraucht. Seine Mächtigkeit und Flexibilität hat aber auch den Nachteil, dass dafür relativ viel Rechenleistung und Speicher benötigt wird. Oft wird gar nicht die Flexibilität einer Liste, sondern nur ihre Fähigkeit, Referenzen auf beliebige Instanzen zu speichern, benötigt. Deshalb existiert in Python neben list noch der Datentyp tuple, der im Gegensatz zu list immutable ist.
Der Datentyp tuple bringt keinen Mehrwert in Bezug auf Funktionalität, denn Listen können alles, was tuple leistet. Tatsächlich steht für tuple-Instanzen nur der Grundstock an Operationen für sequenzielle Datentypen bereit.
Zum Erzeugen neuer tuple-Instanzen dienen die runden Klammern, die – wie bei den Listen – durch Kommata getrennt die Elemente des Tupels enthalten:
>>> a = (1, 2, 3, 4, 5) >>> a[3] 4
Ein leeres Tupel wird durch zwei runde Klammern () ohne Inhalt definiert. Eine Besonderheit ergibt sich für Tupel mit nur einem Element. Würde man versuchen, ein Tupel mit nur einem Element auf die oben beschriebene Weise zu erzeugen, wäre das Literal unter Umständen nicht eindeutig:
>>> kein_tuple = (1) >>> type(kein_tuple) <type 'int'>
Mit (1) wird keine neue tuple-Instanz erzeugt, weil die Klammer in diesem Kontext schon für die Verwendung in Rechenoperationen für Ganzzahlen verwendet wird. Das Problem wird dadurch umgangen, dass in Literalen für Tupel mit nur einem Element diesem Element ein Komma nachgestellt werden muss:
>>> ein_tuple = (1,) >>> type(ein_tuple) <type 'tuple'>
tuple packing und tuple unpacking
Es ist möglich, die umschließenden Klammern bei einer tuple-Definition entfallen zu lassen. Trotzdem werden die durch Kommata getrennten Referenzen zu einem tuple zusammengefasst, was man tuple packing nennt:
>>> datum = 26, 7, 1987 >>> datum (26, 7, 1987)
Umgekehrt ist es möglich, die Werte eines Tupels wieder zu entpacken:
>>> datum = 26, 7, 1987 >>> (tag, monat, jahr) = datum >>> tag 26 >>> monat 7 >>> jahr 1987
Dieses Verfahren heißt tuple unpacking, und auch hier können die umschließenden Klammern entfallen. Durch Kombination von tuple packing und tuple unpacking ist es sehr elegant möglich, die Werte zweier Variablen ohne Hilfsvariable zu tauschen oder mehrere Zuweisungen in einer Zeile zusammenzufassen:
>>> a, b = 10, 20 >>> a, b = b, a >>> a 20 >>> b 10
Richtig angewandt kann die Nutzung dieses Features zur Lesbarkeit von Programmen beitragen, da das technische Detail der Zwischenspeicherung von Daten hinter die eigentliche Absicht, die Werte zu tauschen, zurücktritt.
Immutable heißt nicht zwingend unveränderlich!
Auch wenn tuple-Instanzen immutable sind, können sich die Werte der enthaltenen Elemente auch nach der Erzeugung ändern. Bei der Erzeugung eines neuen Tupels werden die Referenzen festgelegt, die es speichern soll. Verweist eine solche Referenz auf eine Instanz eines mutable Datentyps, beispielsweise eine Liste, so kann sich dessen Wert trotzdem ändern:
>>> a = ([],)
>>> a[0].append("Und sie dreht sich doch!")
>>> a
(['Und sie dreht sich doch!'],)Die Unveränderlichkeit eines Tupels bezieht sich also nur auf die enthaltenen Referenzen und ausdrücklich nicht auf die dahinter stehenden Instanzen.
Dass Tupel immutable sind, ist also keine Garantie dafür, dass sich die Elemente nach der Erzeugung des Tupels nicht mehr verändern.
8.5.3 Strings – str, unicode 

Dieser Abschnitt behandelt Pythons Umgang mit Zeichenketten und insbesondere die Eigenschaften der dafür bereitgestellten Datentypen str und unicode.
Wie Sie im vorhergehenden Kapitel gelernt haben, handelt es sich bei Strings um Folgen von Zeichen. Dies bedeutet, dass alle Operationen für sequenzielle Typen für sie verfügbar sind.
Wir werden uns bis auf Weiteres nur mit str-Instanzen beschäftigen, weil diese anfangs einfacher zu verstehen sind. Aus dem gleichen Grund wird vorerst auf Sonderzeichen wie Umlaute oder das »ß« innerhalb von Strings verzichtet.
Um neue str-Instanzen zu erzeugen, gibt es folgende Literale:
>>> string1 = "Ich wurde mit doppelten Hochkommata definiert" >>> string2 = 'Ich wurde mit einfachen Hochkommata definiert'
Der gewünschte Inhalt des Strings wird zwischen die Hochkommata geschrieben, darf allerdings keine Zeilenvorschübe enthalten (im folgenden Beispiel wurde am Ende der ersten Zeile
gedrückt):
>>> s = "Erste Zeile
File "<stdin>", line 1
s = "Erste Zeile
^
SyntaxError: EOL while scanning single-quoted stringString-Konstanten, die sich auch über mehrere Zeilen erstrecken können, werden durch """ bzw. ''' eingefasst:
>>> string3 = """Erste Zeile!
Ui, noch eine Zeile"""Stehen zwei String-Literale unmittelbar oder durch Leerzeichen getrennt hintereinander, werden sie von Python miteinander zu einem String verbunden:
>>> string = "Erster Teil" "Zweiter Teil"
>>> string
Erster TeilZweiter TeilWie Sie im Beispiel sehen können, sind die Leerzeichen zwischen den Literalen bei der Verkettung nicht mehr vorhanden.
Diese Art der Verkettung eignet sich sehr gut, um lange oder unübersichtliche Strings auf mehrere Programmzeilen aufzuteilen, ohne dass die Zeilenvorschübe und Leerzeichen im Resultat gespeichert werden, wie es bei Strings mit """ oder ''' der Fall wäre. Um diese Aufteilung zu erreichen, schreibt man die String-Teile in runde Klammern:
>>> a = ("Stellen Sie sich einen schrecklich " ... "komplizierten String vor, den man " ... "auf keinen Fall in eine Zeile schreiben " ... "kann.")
Steuerzeichen
Es gibt besondere Text-Elemente, die den Textfluss steuern und sich auf dem Bildschirm nicht als einzelne Zeichen darstellen lassen. Zu diesen sogenannten Steuerzeichen zählen unter anderem der Zeilenvorschub, der Tabulator oder der Rückschritt (von engl. backspace). Die Darstellung solcher Zeichen innerhalb von String-Literalen erfolgt mittels spezieller Zeichenfolgen, sogenannter Escape-Sequenzen. Escape-Sequenzen werden von einem Backslash \ eingeleitet, der von der Kennung des gewünschten Sonderzeichens gefolgt wird. Die Escape-Sequenz "\n" steht beispielsweise für einen Zeilenumbruch:
>>> a = "Erste Zeile\nZweite Zeile"
>>> a
'Erste Zeile\nZweite Zeile'
>>> print a
Erste Zeile
Zweite ZeileBeachten Sie bitte den Unterschied zwischen der Ausgabe mit print und der ohne print im interaktiven Modus. Die print-Anweisung setzt die Steuerzeichen in ihre Bildschirmdarstellung um (bei "\n" wird zum Beispiel eine neue Zeile begonnen), wohingegen die Ausgabe ohne print ein String-Literal mit den Escape-Sequenzen der Sonderzeichen auf dem Bildschirm anzeigt.
Für Steuerzeichen gibt es in Python die folgenden Escape-Sequenzen:
| Escape-Sequenz | Bedeutung |
|
\a |
Bell (BEL) erzeugte einen Signalton. |
|
\b |
Backspace (BS) setzt die Ausgabeposition um ein Zeichen zurück. |
|
\f |
Formfeed (FF) erzeugt einen Seitenvorschub. |
|
\n |
Linefeed (LF) setzt die Ausgabeposition in die nächste Zeile. |
|
\r |
Carriage Return (CR) setzt die Ausgabeposition an den Anfang der nächsten Zeile. |
|
\t |
Horizontal Tab (TAB) hat die gleiche Bedeutung wie die Tabulatortaste. |
|
\v |
Vertikaler Tabulator (VT); dient zur vertikalen Einrückung. |
|
\" |
Doppeltes Hochkomma |
|
\' |
Einfaches Hochkomma |
|
\\ |
Backslash, der wirklich als solcher in dem String erscheinen soll |
Es ist allerdings so, dass Steuerzeichen aus der Zeit stammen, als die Ausgaben hauptsächlich über Drucker erfolgten. Deshalb haben einige dieser Zeichen heute nur noch eine geringe praktische Bedeutung.
Die Escape-Sequenzen für einfache und doppelte Hochkommata sind deshalb notwendig, weil Python diese Zeichen als Begrenzung für String-Literale verwendet. Soll die Art von Hochkomma, die für die Begrenzung eines Strings verwendet wurde, innerhalb dieses Strings als Zeichen vorkommen, muss dort das entsprechende Hochkomma als Escape-Sequenz angegeben werden:
>>> a = "Das folgende Hochkomma muss nicht kodiert werden ' "
>>> b = "Dieses doppelte Hochkomma schon \" "
>>> c = 'Das gilt auch in Strings mit einfachen Hochkommata " '
>>> d = 'Hier muss eine Escape-Sequenz benutzt werden \' 'Im Abschnitt »Zeichensätze und Sonderzeichen« werden wir auf Escape-Sequenzen zurückkommen, um damit beliebige Sonderzeichen wie Umlaute oder das €–Zeichen zu kodieren.
Das automatische Ersetzen von Escape-Sequenzen ist manchmal lästig, insbesondere dann, wenn sehr viele Backslashs in einem String vorkommen sollen. Für diesen Zweck gibt es in Python die Präfixe r oder R, die einem String-Literal vorangestellt werden können. Diese Präfixe markieren das Literal als einen sogenannten Raw-String (dt. roh), was dazu führt, dass alle Backslashs eins zu eins in den Resultat-String übernommen werden:
>>> "Ein \tString mit \\ vielen \nEscape-Sequenzen\t" 'Ein \tString mit \\ vielen \nEscape-Sequenzen\t' >>> r"Ein \tString mit \\ vielen \nEscape-Sequenzen\t" 'Ein \\tString mit \\\\ vielen \\nEscape-Sequenzen\\t' >>> print r"Ein \tString mit \\ vielen \nEscape-Sequenzen\t" Ein \tString mit \\ vielen \nEscape-Sequenzen\t
Wie Sie an den doppelten Backslashs im Literal des Resultats und der Ausgabe mit print sehen können, wurden die Escape-Sequenzen nicht interpretiert.
Stringmethoden
String-Instanzen verfügen zusätzlich zu den Methoden für sequenzielle Datentypen über weitere Methoden, die den Umgang mit Zeichenketten vereinfachen. Aufgrund der großen Anzahl der String-Methoden gibt es anstatt der zusammenfassenden Tabelle aller Methoden mehrere Kategorien, die einzeln erklärt werden.
Wenn im Folgenden von Whitespaces gesprochen wird, sind alle Arten von Zeichen zwischen den Wörtern gemeint, die nicht als eigenes Zeichen angezeigt werden. Whitespaces sind folgende Zeichen: das Leerzeichen, der Zeilenvorschub, der vertikale und horizontale Tabulator, Linefeed, Formfeed und Carriage Return.
Trennen von Strings
Um Strings nach bestimmten Regeln in mehrere Teile zu zerlegen, dienen folgende Methoden:
- s.split([sep[, maxsplit]])
- s.rsplit([sep[, maxsplit]])
- s.splitlines([keepends])
- s.partition(sep)
- s.rpartition(sep)
Die Methoden split und rsplit zerteilen einen String in seine Wörter und geben diese als Liste zurück. Dabei gibt der Parameter sep die Zeichenfolge an, die die Wörter trennt. Mit maxsplit kann die Anzahl der Trennungen begrenzt werden. Wird maxsplit nicht angegeben, wird der String so oft zerteilt, wie sep in ihm vorkommt. Ein gegebenenfalls verbleibender Rest wird als String in die resultierende Liste eingefügt. split beginnt mit dem Teilen am Anfang des Strings, während rsplit am Ende anfängt:
>>> s = "1-2-3-4-5-6-7-8-9-10"
>>> s.split("-")
['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
>>> s.split("-", 5)
['1', '2', '3', '4', '5', '6-7-8-9-10']
>>> s.rsplit("-", 5)
['1-2-3-4-5', '6', '7', '8', '9', '10']Folgen mehrere Trennzeichen aufeinander, werden sie nicht zusammengefasst, sondern es wird jedes Mal erneut getrennt:
>>> s = "1---2-3"
>>> s.split("-")
['1', '', '', '2', '3']Wird sep nicht angegeben, verhalten sich die beiden Methoden anders. Zuerst werden alle Whitespaces am Anfang und am Ende des Strings entfernt, und anschließend wird der String anhand von Whitespaces zerteilt, wobei dieses Mal aufeinanderfolgende Trennzeichen zu einem zusammengefasst werden:
>>> s = " Irgendein \t\t Satz mit \n\r\t Whitespaces"
>>> s.split()
['Irgendein', 'Satz', 'mit', 'Whitespaces']Der Aufruf von split ganz ohne Parameter ist sehr nützlich, um einen Text-String in seine Wörter zu spalten, auch wenn diese nicht nur durch Leerzeichen voneinander getrennt sind.
Die Methode splitlines spaltet einen String in seine einzelnen Zeilen auf und gibt eine Liste zurück, die die Zeilen enthält. Dabei werden Unix-Zeilenvorschübe "\n", Windows-Zeilenvorschübe "\r\n" und Mac-Zeilenvorschübe "\r" als Trennzeichen benutzt:
>>> s = "Unix\nWindows\r\nMac\rLetzte Zeile"
>>> s.splitlines()
['Unix', 'Windows', 'Mac', 'Letzte Zeile']Sollen die trennenden Zeilenvorschübe an den Enden der Zeilen erhalten bleiben, muss für den optionalen Parameter keepends der Wert True übergeben werden.
Die Methode partition zerteilt einen String an der ersten Stelle, an der der übergebene Trennstring sep auftritt, und gibt ein Tupel zurück, das aus dem Teil vor dem Trennstring, dem Trennstring selbst und dem Teil danach besteht. Die Methode rpartition arbeitet genauso, nimmt aber das letzte Vorkommen von sep im Ursprungsstring als Trennstelle:
>>> s = "www.galileo-computing.de" >>> s.partition(".") ('www', '.', 'galileo-computing.de') >>> s.rpartition(".") ('www.galileo-computing', '.', 'de')
Suchen von Teilstrings
Um die Position und die Anzahl der Vorkommen eines Strings in einem anderen String zu ermitteln oder Teile eines Strings zu ersetzen, dienen folgende Methoden:
- s.find(sub[, start[, end]])
- s.rfind(sub[, start[, end]])
- s.index(sub[, start[, end]])
- s.rindex(sub[, start[, end]])
- s.count(sub[, start[, end]])
Die optionalen Parameter start und end der fünf Methoden dienen dazu, den Suchbereich einzugrenzen. Werden start bzw. end angegeben, wird nur der Teilstring s[start:end] betrachtet.
| Hinweis |
| Zur Erinnerung: Beim Slicing eines Strings s mit s[start:end] wird ein Teilstring erzeugt, der das Element s[end] nicht mehr enthält. |
Um herauszufinden, ob und, wenn ja, wo ein bestimmter String in einem anderen vorkommt, bietet Python die Methoden find und index mit ihren Gegenstücken rfind und rindex an. find gibt den Index des ersten Vorkommens von sub in s zurück, rfind entsprechend den Index des letzten Vorkommens. Ist sub nicht in s enthalten, geben find und rfind den Wert -1 zurück:
>>> s = "Mal sehen, wo das 'e' in diesem String vorkommt" >>> s.find("e") 5 >>> s.rfind("e") 29
Die Methoden index und rindex arbeiten auf die gleiche Weise, erzeugen aber einen ValueError, wenn sub nicht in s enthalten ist:
>>> s = "Dieser String wird gleich durchsucht" >>> s.index("wird") 14 >>> s.index("nicht vorhanden") Traceback (most recent call last): File "<pyshell#16>", line 1, in <module> s.index("nicht vorhanden") ValueError: substring not found
Der Grund für diese fast identischen Methoden liegt darin, dass sich Fehlermeldungen unter Umständen eleganter handhaben lassen als ungültige Rückgabewerte. [Sie können die Details in Abschnitt 13.1, »Exception Handling«, nachlesen. ]
Wie oft ein Teilstring in einem anderen enthalten ist, lässt sich mit count ermitteln:
>>> "Fischers Fritze fischt frische Fische".count("sch")
4Ersetzen von Teilstrings
Mit den folgenden Methoden lassen sich bestimmte Teile oder Buchstaben von Strings durch andere ersetzen:
- s.replace(old, new[, count])
- s.lower()
- s.upper()
- s.swapcase()
- s.capitalize()
- s.title()
- s.expandtabs([tabsize])
Die Methode replace gibt einen String zurück, in dem alle Vorkommen von old durch new ersetzt wurden:
>>> falsch = "Python ist nicht super!"
>>> richtig = falsch.replace("nicht", "richtig")
>>> richtig
'Python ist richtig super!'Mit dem Parameter count kann die Anzahl der Ersetzungen begrenzt werden:
>>> s = "Bitte nur die ersten vier e ersetzen" >>> s.replace("e", "E", 4) 'BittE nur diE ErstEn vier e ersetzen'
Die Methode lower ersetzt alle Kleinbuchstaben eines Strings durch die entsprechenden Großbuchstaben und gibt den Ergebnis-String zurück:
>>> s = "ERST GANZ GROSS UND DANN GANZ KLEIN!" >>> s.lower() 'erst ganz gross und dann ganz klein!'
Mit upper erreicht man genau den umgekehrten Effekt.
Die Methode swapcase ändert die Groß- bzw. Kleinschreibung aller Buchstaben eines Strings, indem alle Großbuchstaben durch die entsprechenden Kleinbuchstaben und umgekehrt ersetzt werden:
>>> s = "wENN MAN IM dEUTSCHEN ALLE wORTE SO SCHRIEBE..." >>> s.swapcase() 'Wenn man im Deutschen alle Worte so schriebe...'
Die Methode capitalize gibt eine Kopie des Ursprungsstrings zurück, wobei das erste Zeichen – sofern möglich – in einen Großbuchstaben umgewandelt wurde:
>>> s = "alles klein... noch ;)" >>> s.capitalize() 'Alles klein... noch ;)'
Mit der Methode title wird ein String erzeugt, bei dem alle Wörter groß-, aber ihre restlichen Buchstaben kleingeschrieben sind, wie dies bei Titeln üblich ist:
>>> s = "nOch BIn iCH eheR weNiGEr alS TITeL gEeiGNEt" >>> s.title() 'Noch Bin Ich Eher Weniger Als Titel Geeignet'
Mit expandtabs kann man alle Tabulator-Zeichen ("\t") eines Strings durch Leerzeichen ersetzen lassen. Der optionale Parameter tabsize gibt dabei an, wie viele Leerzeichen für einen Tabulator eingefügt werden sollen. Ist tabsize nicht angegeben, werden acht Leerzeichen verwendet:
>>> s = "\tHier kann Quellcode stehen\n\t\tEine Ebene weiter unten"""
>>> print s.expandtabs(4)
Hier kann Quellcode stehen
Eine Ebene weiter untenEntfernen bestimmter Zeichen am Anfang oder am Ende von Strings
Die strip-Methoden ermöglichen es, unerwünschte Zeichen am Anfang oder am Ende eines Strings zu entfernen:
- s.strip([chars])
- s.lstrip([chars])
- s.rstrip([chars])
Die Methode strip entfernt unerwünschte Zeichen auf beiden Seiten des Strings. lstrip entfernt nur die Zeichen auf der linken Seite und rstrip nur die Zeichen auf der rechten.
Für den optionalen Parameter chars kann ein String übergeben werden, der die Zeichen enthält, die entfernt werden sollen. Wird chars nicht angegeben, werden alle Whitespaces entfernt:
>>> s = " \t\n \rUmgeben von Whitespaces \t\t\r" >>> s.strip() 'Umgeben von Whitespaces' >>> s.lstrip() 'Umgeben von Whitespaces \t\t\r' >>> s.rstrip() ' \t\n \rUmgeben von Whitespaces'
Um beispielsweise alle umgebenden Ziffern zu entfernen, könnte man so vorgehen:
>>> ziffern = "0123456789" >>> s = "3674784673546Versteckt zwischen Zahlen3425923935" >>> s.strip(ziffern) 'Versteckt zwischen Zahlen'
Ausrichten von Strings
Die folgenden Methoden erzeugen einen String mit einer bestimmten Länge und richten den Ursprungsstring darin auf eine bestimmte Weise aus:
- s.center(width[, fillchar])
- s.ljust(width[, fillchar])
- s.rjust(width[, fillchar])
- s.zfill(width)
Mit dem Parameter width wird die gewünschte Länge des neuen Strings angegeben. Ist die Länge von s größer als width, wird eine Kopie von s zurückgegeben. Die Methode center zentriert s im neuen String, ljust richtet s links aus, rjust richtet s rechts aus. Der optionale Parameter fillchar der drei ersten Methoden muss ein String der Länge eins sein und gibt das Zeichen an, das zum Auffüllen bis zur übergebenen Länge verwendet werden soll. Standardmäßig werden Leerzeichen zum Füllen benutzt:
>>> s = "Richte mich aus" >>> s.center(50) ' Richte mich aus ' >>> s.ljust(50) 'Richte mich aus ' >>> s.rjust(50, "-") '-----------------------------------Richte mich aus'
Die Methode zfill ist ein Spezialfall von rjust und für Strings gedacht, die numerische Werte enthalten. zfill erzeugt einen String der Länge width, in dem der Ursprungsstring rechts ausgerichtet ist und die linke Seite mit Nullen aufgefüllt wurde:
>>> "13.37".zfill(20) '00000000000000013.37'
String-Tests
Die folgenden Methoden geben einen Wahrheitswert zurück, der aussagt, ob der Inhalt des Strings eine bestimmte Eigenschaft hat. Mit islower beispielsweise kann man prüfen, ob alle Buchstaben in s Kleinbuchstaben sind.
| Methode | Beschreibung |
|
s.isalnum() |
True, wenn alle Zeichen in s Buchstaben oder Ziffern sind |
|
s.isalpha() |
True, wenn alle Zeichen in s Buchstaben sind |
|
s.isdigit() |
True, wenn alle Zeichen in s Ziffern sind |
|
s.islower() |
True, wenn alle Buchstaben in s Kleinbuchstaben sind |
|
s.isupper() |
True, wenn alle Buchstaben in s Großbuchstaben sind |
|
s.isspace() |
True, wenn alle Zeichen in s Whitespaces sind |
|
s.istitle() |
True, wenn alle Wörter in s großgeschrieben sind |
Da sich diese Methoden alle sehr ähneln, soll ein Beispiel an dieser Stelle ausreichen:
>>> s = "1234abcd" >>> s.isdigit() False >>> s.isalpha() False >>> s.isalnum() True
Um zu prüfen, ob ein String mit einer bestimmten Zeichenkette beginnt oder endet, dienen die Methoden startswith bzw. endswidth:
- s.startswidth(prefix[, start[, end]])
- s.endswidth(suffix[, start[, end]])
Die optionalen Parameter start und end können dabei – wie schon bei den Suchen- und Ersetzen-Methoden – die Abfrage auf einen bestimmten Bereich von s begrenzen:
>>> s = "www.galileo-computing.de"
>>> s.startswith("www.")
True
>>> s.endswith(".de")
True
>>> s.startswith("galileo", 4)
TrueVerkettung von Elementen in sequenziellen Datentypen
Eine häufige Aufgabe ist es, eine Liste von Strings mit einem Trennzeichen zu verketten. Beispielsweise könnte man die Namen in einer Kontaktliste seines Instant-Messengers durch Kommata getrennt ausgeben wollen. Für diesen Zweck stellt Python die Methode join zur Verfügung:
- s.join(seq)
Der Parameter seq ist dabei ein beliebiges iterierbares Objekt, dessen Elemente alle Strings sein müssen. Die Elemente von seq werden mit s als Trennzeichen verkettet. Kommen wir auf unser Kontaktlistenbeispiel zurück:
>>> kontakt_liste = ["Fix", "Foxy", "Lupo", "Dr. Knox"] >>> ", ".join(kontakt_liste) 'Fix, Foxy, Lupo, Dr. Knox'
Wird für seq ein String übergeben, so ist das Ergebnis die Verkettung aller Buchstaben, jeweils durch s voneinander getrennt:
>>> satz = "Stoiber-Satz"
>>> "...ehm...".join(satz)
'S...ehm...t...ehm...o...ehm...i...ehm...b...ehm...e...ehm...r...ehm...-...ehm...S...ehm...a...ehm...t...ehm...z'Formatierung
Oft möchte man seine Bildschirmausgaben auf bestimmte Weise anpassen. Um beispielsweise eine dreispaltige Tabelle von Zahlen anzuzeigen, müssen abhängig von der Länge der Zahlen Leerzeichen eingefügt werden, damit die einzelnen Spalten untereinander angezeigt werden. Eine Anpassung der Ausgabe ist auch nötig, wenn man einen Geldbetrag ausgeben möchte, der in einer float-Instanz gespeichert ist, die mehr als zwei Nachkommastellen besitzt.
Für die Lösung solcher Probleme gibt es in Python den Formatierungsoperator für Strings, das Prozentzeichen %. Er erwartet zwei Operanden: als ersten Operanden einen String, der die Formatierung beschreibt, und als zweiten eine Sequenz, in der die Werte gespeichert sind, die man formatiert ausgeben möchte. Die Formatierungsbeschreibungen in dem String werden durch ein Prozentzeichen eingeleitet, dem im einfachsten Fall ein einzelner Buchstabe folgt. Dieser Buchstabe gibt an, welche Art von Daten man an dieser Stelle einfügen möchte. Ein d steht beispielsweise für eine Ganzzahl:
>>> "Es ist %d:%d Uhr" % (13, 37)
'Es ist 13:07 Uhr'Es ist auch möglich, einen einzelnen Wert anstatt der Sequenz zu übergeben:
>>> x = 10
>>> "Der Wert von x ist %d" % x
'Der Wert von x ist 10'Allerdings muss in jedem Fall die Anzahl der Formatierungsanweisungen mit der Anzahl der Werte übereinstimmen. Werden mehr oder weniger Werte als Formatierungsanweisungen übergeben, führt dies zu einem Fehler:
>>> "Nur %d Formatierungsanweisungen" % (1, 1337) Traceback (most recent call last): File "<pyshell#53>", line 1, in <module> "Nur %d Formatierungsanweisungen" % (1, 1337) TypeError: not all arguments converted during string formatting
Das Ergebnis der Formatierung ist ein neuer String, in dem alle Formatierungsanweisungen in dem Ursprungsstring durch die entsprechenden Werte der Sequenz ersetzt wurden.
Es existieren die folgenden Ausgabedatentypen:
| Kennung | Beschreibung |
|
d |
Ganzzahl mit Vorzeichen |
|
i |
Ganzzahl mit Vorzeichen |
|
o |
Oktalzahl ohne Vorzeichen |
|
u |
Ganzzahl ohne Vorzeichen |
|
x |
Hexadezimalzahl ohne Vorzeichen in Kleinbuchstaben |
|
X |
Hexadezimalzahl ohne Vorzeichen in Großbuchstaben |
|
e |
Fließkommazahl im wissenschaftlichen Format (kleines »e«) |
|
E |
Fließkommazahl im wissenschaftlichen Format (großes »E«) |
|
f |
Fließkommazahl in Dezimalschreibweise |
|
F |
Wie f |
|
g |
Fließkommazahl in wissenschaftlicher Schreibweise, wenn der Exponent kleiner als –4 ist, sonst in Dezimalschreibweise |
|
G |
Wie g |
|
c |
Zeichen (kann Strings der Länge eins und Ganzzahlen mit ASCII-Codes umwandeln) |
|
r |
String (macht aus jeder Instanz einen String mit der Builtin-Function repr) |
|
s |
String (macht aus jeder Instanz einen String mit der Builtin-Function str) |
|
% |
Gibt ein Prozentzeichen aus |
Zwischen dem Prozentzeichen und dem Ausgabedatentyp können weitere Angaben gemacht werden, um die Ausgabe zu steuern. Betrachten wir ein Beispiel mit allen möglichen Angaben:
>>> "%+10.2f" % 123.45678 ' +123.46'
Das Pluszeichen + am Anfang ist ein sogenanntes Umwandlungsflag und sorgt dafür, dass bei Zahlen das Vorzeichen immer mit ausgegeben wird. Mit der Zahl 10 nach dem Pluszeichen wird angegeben, wie viele Zeichen das Resultat auf jeden Fall haben soll. Wenn die angegebene Mindestlänge unterschritten wird, füllt Python von links so lange mit Leerzeichen auf, bis der String lang genug ist. Die letzte Angabe, die aus einem Punkt und einer Zahl .2 besteht, bestimmt die sogenannte Genauigkeit der Ausgabe. Ist keine Genauigkeit angegeben, wird für numerische Werte der Standardwert 6 und für nichtnumerische Werte eine unendlich große Zahl verwendet. Bei Fließkommazahlen bestimmt die Genauigkeit die Anzahl der angezeigten Nachkommastellen, bei Zahlen in Exponentialschreibweise die Anzahl geltender Ziffern und bei Strings die maximale Länge der Formatierung.
Python stellt fünf Umwandlungsflags zur Verfügung:
| Flag | Bedeutung |
|
# |
Setzt die Ausgabe in den alternativen Modus (wird im Folgenden erklärt). |
|
0 |
Wenn die Mindestlänge bei numerischen Werten unterschritten wird, füllt Python mit der 0 anstatt mit Leerzeichen von links auf. |
|
- |
Wird die Mindestlänge unterschritten, wird anstatt von links von rechts aufgefüllt. |
|
(ein Leerzeichen) |
Vor einem numerischen Wert mit positivem Vorzeichen wird ein Leerzeichen eingefügt. |
|
+ |
Vor numerischen Werten wird das Vorzeichen ausgegeben. |
Es ist möglich, mehrere Umwandlungsflags hintereinander anzugeben:
>>> "%0+10.2f" % 123.45678
'+000123.46'Widersprechen sich die angegebenen Umwandlungsflags, wird die Angabe verwendet, die in der obigen Tabelle weiter unten steht: Wenn 0 und das Minuszeichen angegeben sind, wird die 0 ignoriert. Sind das Leerzeichen und + angegeben, wird das Leerzeichen nicht beachtet.
Der durch das Umwandlungsflag # gesetzte alternative Modus verändert die Ausgabe einiger Ausgabedatentypen wie folgt:
| Kennung | Beschreibung |
|
o |
Vor der Oktalzahl wird eine Null (0) eingefügt, wenn dort noch keine stand. |
|
x |
Vor der Hexadezimalzahl wird die Zeichenfolge 0x ausgegeben. |
|
X |
Wie bei x, aber statt 0x mit 0X |
|
e |
Es wird immer ein Dezimalpunkt ausgegeben, auch wenn keine Nachkommastellen folgen. |
|
E |
Wie bei e |
|
f |
Wie bei e |
|
F |
Wie bei e |
|
g |
Wie bei e; zusätzlich werden Nullen am Ende nicht entfernt, wie es sonst der Fall wäre. |
|
G |
Wie bei g |
Die Wirkungsweise des alternativen Modus wird durch die folgenden Beispiele noch einmal verdeutlicht:
>>> "%o vs. %#o" % (26, 26)
'32 vs. 032'
>>> "%x vs. %#x" % (26, 26)
'1a vs. 0x1a'
>>> "%5.0e vs. %#5.0e" % (123.4567, 123.4567)
'1e+002 vs. 1.e+002'
>>> "%g vs. %#g" % (1337, 1337)
'1337 vs. 1337.00'Alternative Angabe von Werten
Insbesondere wenn in einem String sehr viele Werte formatiert werden sollen, ist die oben beschriebene Methode, bei der die Werte in einer Sequenz angegeben werden, sehr unübersichtlich. Python bietet deshalb eine Möglichkeit an, die Formatierungsanweisungen mit Namen zu versehen:
>>> s = "%(vorname)s %(nachname)s (%(alter)d) sucht..."
>>> s % {"vorname" : "Heinz", "nachname" : "Meier", "alter" : 30}
'Heinz Meier (30) sucht...'Die Namen werden in dem Formatstring direkt hinter dem Prozentzeichen in runden Klammern angegeben.
Dem Formatierungsoperator muss dann anstelle der Wertesequenz eine Zuordnung von Namen und Werten folgen. Diese Zuordnung wird von geschweiften Klammern begrenzt, die eine durch Kommata getrennte Liste von Name-Wert-Paaren umschließen. In den Paaren werden die Namen durch Doppelpunkte von den dazugehörigen Werten getrennt. [Bei diesen Zuordnungen handelt es sich um den Python-Datentyp Dictionary, den wir ausführlich in Abschnitt 8.6.1 behandeln. ]
Als dritte und letzte Möglichkeit der Werteübergabe ist es möglich, auch die Mindestlänge von dem Format-String in die Wertesequenz zu verlagern. Um dies zu erreichen, wird in den Formatstring anstelle der Mindestlänge ein Sternchen * geschrieben. In der Wertesequenz werden dann zwei Werte für diese Formatierung benutzt: Zuerst wird die Länge und dann der eigentliche Wert gelesen:
>>> "Freie Platzwahl: %*d" % (5, 123) 'Freie Platzwahl: 123'
Im obigen Beispiel wurde die Zahl 123 auf eine Breite von 5 Stellen formatiert. Man kann die direkte Breitenangabe innerhalb des Format-Strings mit der Angabe innerhalb der Sequenz kombinieren, wie das folgende Beispiel demonstriert:
>>> "Im Format-String: %6d. In der Sequenz: %*d" % (11, 3, 7)
'Im Format-String: 11. In der Sequenz: 7'Hier wurde die Zahl 11 direkt über den Formatstring auf eine Mindestlänge von sechs Zeichen formatiert, während die 7 durch die in dem Tupel angegebene Zahl 3 formatiert wurde.
Zeichensätze und Sonderzeichen
Bisher haben wir uns der Einfachheit halber nur mit Strings beschäftigt, die keine Sonderzeichen (wie Umlaute oder das €-Zeichen) beinhalten. Die Besonderheiten beim Umgang mit solchen Zeichen liegen zum Teil an der geschichtlichen Entwicklung der Zeichenkodierung. Deshalb werden wir diese im Folgenden kurz umreißen.
Zuerst müssen wir eine Vorstellung davon entwickeln, wie ein Computer intern mit Zeichenketten umgeht. Generell lässt sich sagen, dass der Computer eigentlich überhaupt keine Zeichen kennt, da sich in seinem Speicher nur Zahlen befinden. Um trotzdem Bildschirmausgaben zu produzieren oder andere Operationen mit Zeichen durchzuführen, hat man deshalb Übersetzungstabellen, die sogenannten Codepages (dt. Zeichensatztabellen) definiert, die jedem Buchstaben eine bestimmte Zahl zuordnen. Der bekannteste und wichtigste Zeichensatz ist durch die ASCII-Tabelle [American Standard Code for Information Interchange (dt. Amerikanische Standardkodierung für den Informationsaustausch) ] festgelegt.
Durch diese Zuordnung werden neben den Buchstaben und Ziffern auch Satz- und einige Sonderzeichen abgebildet. Außerdem existieren nicht druckbare Steuerzeichen, wie der Tabulator oder der Zeilenvorschub. Die ASCII-Tabelle ist eine 7-Bit-Zeichenkodierung, das bedeutet, dass von jedem Buchstaben 7Bit Speicherplatz belegt werden. Es können also 27 = 128 verschiedene Zeichen abgebildet werden. Die Definition des ASCII-Zeichensatzes orientiert sich am Alphabet der englischen Sprache, das insbesondere keine Umlaute wie »ä« oder »ü« enthält. Um auch solche Sonderzeichen in Strings abspeichern zu können, erweiterte man den ASCII-Code, indem man den Speicherplatz für ein Zeichen um ein Bit auf 28 = 256 Möglichkeiten erhöhte, was 128 Plätze für weitere Sonderzeichen bot. Welche Interpretation konkret für diese weiteren Plätze verwendet wird, hängt von der verwendeten Codepage ab und unterscheidet sich in der Regel zwischen verschiedenen Plattformen.
Pythons str-Datentyp implementiert einen solchen 8-Bit-String und ist im Prinzip nichts anderes als eine Kette von Bytes. Um den Zahlenwert eines Zeichens zu ermitteln, gibt es in Python die Built-in-Function ord, die als einzigen Parameter einen String der Länge eins erwartet:
>>> ord("j") 106 >>> ord("[") 91
Umgekehrt liefert die Built-in-Function chr das zu einem Byte gehörige Zeichen:
>>> chr(106) 'j'
>>> chr(91) '['
Die Beispiele oben beziehen sich nur auf Zeichen mit Ordnungszahlen, die kleiner als 128 sind und damit noch im ASCII-Bereich liegen. Interessanter ist das folgende Beispiel:
>>> ord("ä")
228Auf dem Computer, der dieses Beispiel ausgeführt hat, läuft eine Version von Microsoft Windows für Westeuropa, die standardmäßig eine Codepage mit dem Namen »Windows-1252« verwendet. »Windows-1252« bildet alle wichtigen Zeichen für Westeuropa, das Eurozeichen inbegriffen, ab. Wenn Sie das Beispiel ausführen und eine andere Zahl als 228 auf dem Bildschirm sehen, liegt das einfach daran, dass Ihr Computer eine andere Codepage als »Windows-1252« verwendet.
Wir haben uns bereits während der Einführung zu Strings mit Escape-Sequenzen beschäftigt. In Bezug auf Sonderzeichen spielen sie eine zentrale Rolle:
>>> "Überprüfung der Änderungen" '\xdcberpr\xfcfung der \xc4nderungen'
Was auf den ersten Blick kryptisch erscheint, hat eine einfache Struktur: Wie Sie bereits wissen, wird durch den Backslash \ innerhalb von String-Literalen eine Escape-Sequenz eingeleitet. Die Escape-Sequenz mit der Kennung x ermöglicht es, einzelne Bytes in str-Instanzen direkt zu kodieren. Sie erwartet eine zweistellige Hexadezimalzahl als Parameter, die direkt hinter das x geschrieben wird. Der Wert dieses Parameters gibt den Zahlenwert des Bytes an, im Beispiel also 0xdc = 220 ("Ü"), 0xfc = 252 ("ü") und 0xc4 = 196 ("Ä"). Diese Zahlen hat Python der aktuellen Codepage entnommen, in der sie genau den angegebenen Zeichen entsprechen:
>>> print chr(220), chr(252), chr(196)
Ü ü ÄDiese Kodierung von Sonderzeichen hat den Vorteil, dass der Quelltext nur aus normalen ASCII-Zeichen besteht und beim Abspeichern und Verteilen nicht mehr auf die verwendete Codepage geachtet werden muss.
Allerdings bringt eine solche Kodierung zwei wichtige Nachteile mit sich: Zum einen ist die Anzahl möglicher Zeichen auf 256 begrenzt, und zum anderen muss jemand, der einen so kodierten String verarbeiten will, wissen, welche Codepage verwendet wurde, weil sich viele Codepages widersprechen. Den zweiten Nachteil kann man eher als Schönheitsfehler betrachten, da eine einfache Lösung darin besteht, einfach zu jedem String die verwendete Kodierung mit anzugeben. Ein wirklicher Mangel ist dagegen die Begrenzung der Zeichenanzahl. Stellen Sie sich mal einen String vor, der eine Ausarbeitung über Autoren aus verschiedenen Sprachräumen mit Originalzitaten enthält: Sie würden aufgrund der vielen verschiedenen Alphabete sehr schnell an die Grenze der 8-Bit-Kodierung stoßen und könnten das Werk nicht digitalisieren. Oder stellen Sie sich vor, Sie wollen einen Text in chinesischer Sprache kodieren, was durch die über 10.000 Schriftzeichen unmöglich würde.
Ein naheliegender Lösungsansatz für dieses Problem bestand darin, den Speicherplatz pro Zeichen zu erhöhen, was aber neue Nachteile mit sich brachte. Verwendet man beispielsweise 16 Bits für jedes einzelne Zeichen, ist die Anzahl der Zeichen immer noch auf 65.536 begrenzt, und man muss davon ausgehen, dass die Sprachen sich weiterentwickeln werden und somit auch diese Anzahl einmal nicht mehr ausreichen wird. [Es ist tatsächlich so, dass 16 Bit schon heute nicht mehr ausreichen, um alle Zeichen der menschlichen Sprache zu kodieren. ] Außerdem würde sich im 16-Bit-Beispiel der Speicherplatzbedarf für einen String verdoppeln, weil für jedes Zeichen doppelt so viele Bits wie bei erweiterter ASCII-Kodierung verwendet würden, und das, obwohl ein Großteil aller Texte hauptsächlich aus einer kleinen Teilmenge aller vorhandenen Zeichen besteht. Die einfache Speicherplatzerhöhung für jedes einzelne Zeichen ist also keine wirkliche Lösung, denn das Problem wird irgendwann wieder auftreten, wenn die neu gesetzte Schranke erneut überschritten wird. Außerdem wird unnötig Speicherplatz vergeudet.
Eine langfristige Lösung für das Kodierungsproblem wurde schließlich durch den Standard namens Unicode erarbeitet, der variable Kodierungslängen für einzelne Zeichen vorsieht. Im Prinzip ist Unicode eine riesige Tabelle, die jedem bekannten Zeichen eine Zahl, den sogenannten Codepoint zuweist. Diese Tabelle wird vom Unicode Consortium, einer gemeinnützigen Institution, gepflegt und ständig erweitert. Codepoints werden in der Regel als »U+x« geschrieben, wobei x die hexadezimale R



