Datentypen und Variablen

Einführung

Auch wenn man Variablen und Datentypen von anderen Programmiersprachen bereits zur Genüge zu kennen glaubt, sollte man dieses Kapitel dennoch zumindest überfliegen, denn einiges ist eben doch anders in Python.

Variablen

Unvermeidliche Entscheidungen Eine Variable im allgemeinsten Sinne ist einfach ein Behälter (Container) zur Aufbewahrung von bestimmten Werten, also z.B. Strings oder Zahlen. Man kann im Verlauf des Programms auf diese Variablen, oder genauer auf den Wert ihres Inhaltes zugreifen, oder ihnen einen neuen Wert zuweisen.
In den meisten Programmiersprachen, wie z.B. C, ist es so, dass eine Variable einen festen Speicherplatz bezeichnet, in dem Werte eines bestimmten Datentyps abgelegt werden können. Während des Programmlaufes kann sich der Wert der Variable ändern, aber die Wertänderungen müssen vom gleichen Typ sein. Also man kann nicht in einer Variable zu einem bestimmten Zeitpunkt eine Integerzahl gespeichert haben und dann diesen Wert durch eine Fließkommazahl überschreiben. Ebenso ist der Speicherort der Variablen während des gesamten Laufes konstant, kann also nicht mehr geändert werden. In Sprachen wie C wird der Speicherort bereit durch den Compiler fixiert.
In Python sieht dies anders aus. Zunächst einmal bezeichnen Variablen in Python keinen bestimmten Typ und deshalb benötigt man auch in Python keine Typdeklaration. Benötigt man im Programm bespielsweise eine Variable i mit dem Wert 42, so erreicht man dies einfach mit der folgenden Anweisung:

i = 42
Obige Anweisung darf man nicht als mathematisches Gleichheitszeichen sehen, sondern als "der Variablen i wird der Wert 42 zugewiesen", d.h. der Inhalt von i ist nach der Zuweisung 42. Man kann diesen Wert der Variablen auch, wie man im folgenden Beispiel sieht, anschließend ändern:
 >>> i = 42
>>> i = i + 1
>>> print i
43
>>> 

Zahlen

Python kennt vier eingebaute (built-in) Datentypen für Zahlen:

Strings

Ein String, oder Zeichenkette, kann man als eine Sequenz von einzelnen Zeichen sehen.

String Indizierung

Jedes einzelne Zeichen eines Strings, kann über einen Index angesprochen werden. Im folgenden Beispiel sehen wir, wie der obige im Bild dargestellt String in Python definiert wird und wie wir auf ihn zugreifen können:

>>> s = "Python"
>>> print s[0]
P
>>> print s[3]
h
Die Länge eines Strings kann man mit der Funktion len() bestimmen und damit kann man auch einfach beispielsweise auf das letzte oder vorletzte Zeichen eines Strings zugreifen:
>>> s = "Python"
>>> index_last_char = len(s) - 1
>>> print s[index_last_char]
n
>>> print s[index_last_char - 1]
o
>>> 
Da es bei der praktischen Arbeit sehr häufig vorkommt, dass man auf einzelne Zeichen eines Strings von hinten zugreifen muss, wäre es sehr lästig, wenn man dies immer über den Umweg durch den Aufruf der Funktion len() machen müsste. Python bietet deshalb eine elegantere Möglichkeiten. Die Indices werden auch von rechts durch negative Indices nummeriert, d.h. das letzte Zeichen wird mittels des Index -1, das vorletzte mittels -2 usw. angesprochen. Wir sehen dies in der folgenden Abbildung veranschaulicht:

String Index negativ

Im Code sieht das wie folgt aus:
>>> s = "Python"
>>> last_character = s[-1]
>>> print last_character
n


Strings können unter Benutzung von angegeben werden.

Wichtige Stringfunktionen

Ein paar String-Funktionen:

Unveränderliche Zeichenketten

Wie in Java aber nicht wie in C oder C++, können Strings in Python nicht verändert werden. Versucht man eine indizierte Position zu ändern, erzeugt man eine Fehlermeldung:
>>> s = "Some things are immutable!"
>>> s[-1] = "."
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> 

Escape- oder Fluchtzeichen

Es gibt Zeichenfolgen, die den Textfluss steuern, wie zum Beispiel ein Newline (Zeilenvorschub) oder Tabulator. Sie lassen sich nicht auf dem Bildschirm als einzelne Zeichen darstellen. Die Darstellung solcher Zeichen innerhalb von String-Literalen erfolgt mittels spezieller Zeichenfolgen, sogenannter Escape-Sequenzen. Eine Escape-Sequenz wird von einem Backslash \ eingeleitet, gefolgt von der Kennung des gewünschten Sonderzeichens. Übersicht der Escape-Zeichen: Die Auswertung von Escape-Zeichen kann man verhindern, indem man einem String ein r oder R unmittelbar voranstellt.
Beispiel:
r"\n bewirkt einen Zeilenvorschub"

Typwechsel bei Variablen

In Python kann eine Variable, wie bereits gesagt, sofort ohne Deklaration des Datentyps verwendet werden. Dennoch vergibt Python einen Datentyp, d.h. je nach Datentyp, wird die Variable anders angelegt, also als Integer, Float, String, und so weiter. Eigentlich müsste man sagen, dass eine Objekt mit einem bestimmten Datentyp bzw. Klasse angelegt wird. Die Variable referenziert dann dieses Objekt, d.h. die Variable selbst hat also eigentlich keinen Typ. Anders ausgedrückt
Der Datentyp ist in Python nicht an die Variable, sondern an den Wert gebunden, was impliziert, dass sich der Typ zur Laufzeit ändern kann, wie wir im folgenden Beispiel sehen können:
i = 42		# Datentyp ist integer (implizit)
i = 42 + 0.11	# Typ ändert sich zu float
i = "fourty"	# und jetzt ein String   

Wechselnde Speicherorte

Prinzipiell wird sich im vorigen Fall, wobei das natürlich implementierungsabhängig ist, der Speicherort für die Variable i ändern. Der Interpreter kann bei der Anweisung "i = 42" den Wert als Integer abspeichern, muss aber bei der Anweisung "i = 42 + 0.11" einen neuen Ort für eine Float-Zahl anlegen. Für i = "fourty" muss er in einen String gewandelt werden.
Achtung: Als Anwender braucht man dies eigentlich nicht zu wissen, da ja alles automatisch geschieht!

Betrachten wir nun folgenden Python-Code:
>>> x = 3
>>> y = x
>>> y = 2
Variablen und
							 Speicherorte schematisch
Intuitiv würde man davon ausgehen, dass Python zunächst für x einen Speicherort wählt und dort das Objekt (Zahl) 3 abspeichert. Anschließend wird der Variablen y der Wert von x zugewiesen. In C und vielen anderen Programmiersprachen würde auch für y ein eigener Speicherort bestehen, in dem nun die Zahl 3 hineingeschrieben würde. Python geht anders vor: x ist eine Variable mit dem Objekt 3 und y ist eine Variable mit dem "selben" (nicht "gleichen") Objekt. x und y "zeigen" auf das gleiche Objekt. In der letzten Zeile wird y nun der Wert 2 zugewiesen, jetzt muss ein neues Objekt angelegt werden und y "zeigt" auf einen neuen Speicherort. (Anm: Dieses eben verwendete "zeigen" sollte von C-Programmierern keinesfalls mit den unter C verwendeten Pointern verwechselt werden.)

Es stellt sich nun die Frage, wie man das oben gesagte überprüfen kann. Dazu bietet sich die Identitätsfuntion id() an. Die Identität einer Instanz dient dazu, sie von allen anderen Instanzen zu unterscheiden. Die Identität ist eine Ganzzahl, und sie ist innerhalb eines Programmes eindeutig. Die Identitätsfunktion id() liefert die Identität. So kann man prüfen, ob es sich um eine bestimmte Instanz handelt und nicht nur um eine mit dem gleichen Wert und Typ. Wir geben nochmals das obige Beispiel ein, lassen uns aber jeweils die Identität ausgeben:
>>> x = 3
>>> print id(x)
157379912
>>> y = x
>>> print id(y)
157379912
>>> y = 2
>>> print id(y)
157379924
>>> print id(x)
157379912
>>> 
Wir stellen fest, dass sich die Identität erst ändert, nachdem wir y einen neuen Wert zugewiesen haben. Die Identität von x bleibt gleich, d.h. der Speicherort von x wird nicht geändert.

Besonderheiten bei Strings

Einen besonderen Effekt können wir bei Strings feststellen. Im folgenden Beispiel wollen wir dies veranschaulichen. Dazu benötigen wir noch den "is"-Operator. Sind a und b zwei Strings, dann prüft "a is b", ob a und b die gleiche Identität (Speicherort) haben. Wenn "a is b" gilt, dann gilt auch "a == b". Aber wenn "a == b" gilt, dann gilt natürlich nicht notwendigerweise auch "a is b"!
Nun wollen wir untersuchen, wie Strings in Python abgespeichert werden. Im folgenden Beispiel, erkennen wir, dass a und b sich den gleichen Speicherort teilen, obwohl wir diesmal keine Zuweisung der Art "b = a" verwendet haben:
>>> a = "Linux"
>>> b = "Linux"
>>> a is b
True
Wie sieht es jedoch aus, wenn der verwendete String länger ist? Im folgenden verwenden wir als String den längsten Ortsnamen der Welt. Eine Gemeinde mit etwas mehr als 3000 Einwohnern im Süden der Insel Anglesey in der gleichnamigen Grafschaft im Nordwesten von Wales:
>>> a = "Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch"
>>> b = "Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch"
>>> a is b
True
Aber Vorsicht ist geboten, denn was für eine Gemeinde in Wales funktioniert, schlägt beispielsweise für Baden-Württemberg fehl:
>>> a = "Baden-Württemberg"
>>> b = "Baden-Württemberg"
>>> a is b
False
>>> a == b
True
Also an der geographischen Lage kann es nicht liegen, wie man im folgenden Beispiel sieht. Es sieht vielmehr so aus, als dürften keine Sonderzeichen oder Blanks im String vorkommen.
>>> a = "Baden!"
>>> b = "Baden!"
>>> a is b
False
>>> a = "Baden1"
>>> b = "Baden1"
>>> a is b
True