Programmieren lernen in fünf Schritten

Aus LinuxUser 09/2006

Programmieren lernen in fünf Schritten

Einstieg in Python

Ob Sie nur ein kleines Administrationsskript entwickeln oder eine umfangreiche Anwendung entwickeln – mit Python geht beides leicht von der Hand.

Python ist vielseitig. Die Programmiersprache, deren Entwicklung Anfang der 90er Jahre ihren Anfang nahm, eignet sich gleichermaßen für kleine wie sehr große Projekte. Python gibt es für Linux, viele Unix-Derivate, Mac OS X, Windows und auch für Plattformen wie OS/2 oder Nokia-S60-Mobiltelefone.

Die Python-Standard-Distribution (CPython), die man von der Python-Website [1] herunterladen kann, enthält rund 350 Module, unter anderem zum Umgang mit Posix-Signalen und Threads, regulären Ausdrücken sowie zum Abrufen von Webseiten und Parsen von E-Mails. Ein Debugger zur Codeanalyse und ein Profiler zur Messung der Ausführungsgeschwindigkeit zählen zum Lieferumfang der Standard-Distribution. Neben einer ausführlichen, englischsprachigen Dokumentation [2] gibt es auch eine hervorragende Python-Kurzreferenz [3].

Im Internet finden sich viele weitere Bibliotheken, beispielsweise zur PDF-Erzeugung [6], zur Spieleprogrammierung [5] oder zum Erstellen spezieller Parser [4]. Eine umfangreiche Liste bietet der Python Package Index (PyPI) [11]. Es gibt Schnittstellen zu diversen GUI-Toolkits wie Tk [7], GTK [8], wxWindows [9] und Qt [10]. Abbildung 1 zeigt die in Python mit Tk geschriebenen Entwicklungsumgebung Idle.

Abbildung 1: IDLE, eine in Python mit der Tk-Bibliothek programmierte integrierte Entwicklungsumgebung. Je nach Linux-Distribution wird diese IDE zusammen mit Python oder aus einem getrennten Paket installiert.

Abbildung 1: IDLE, eine in Python mit der Tk-Bibliothek programmierte integrierte Entwicklungsumgebung. Je nach Linux-Distribution wird diese IDE zusammen mit Python oder aus einem getrennten Paket installiert.

Python eignet sich nicht nur zum Skripting, man kann damit auch umfangreiche Programme schreiben. Bei den Paketverwaltungstools von Gentoo Linux handelt es sich hauptsächlich um Python-Skripte. Bekannte Python-Anwendungen sind das Dateitransferprogramm BitTorrent, der Mailinglistenmanager Mailman, der Applikationsserver Zope, das Vektorgrafikprogramm Skencil und das Online-Spiel Eve.

Python lässt sich leicht erlernen und ermutigt zum Schreiben von gut verständlichem Code. Es räumt der Geschwindigkeit des Entwickelns den Vorrang gegenüber der Geschwindigkeit der Programmausführung ein. Das heißt aber nicht, dass Python-Programme grundsätzlich träge arbeiten: Die Struktur der Sprache erlaubt das Implementieren optimaler Algorithmen, zudem sind viele interne Python-Funktionen in C geschrieben.

Installation

Viele Linux-Distributionen richten Python bereits bei der Installation mit ein, so gut wie alle bieten es als Paket an. Um herauszufinden, ob Ihr System Python bereits mitbringt, geben Sie in der Shell den Befehl python -V ein. Ist Python eingerichtet, antwortet es mit der Ausgabe der Versionsnummer. Die aktuellste Version für den Produktionseinsatz trägt die Nummer 2.4.3.

Falls Sie eine Fehlermeldung erhalten, installieren Sie Python aus den Paketen Ihrer Distribution nach. Bei einigen Linux-Spielarten müssen Sie zur Einrichtung mancher Python-Erweiterungen zusätzliche Pakete installieren, die python-dev, python-headers oder ähnlich heißen.

Spielerei

Für erste Tests, aber auch zum Experimentieren während der Entwicklung, eignet sich der Python-Interpreter im interaktiven Modus (Listing 1). Geben Sie den Python-Code am Prompt >>> ein. Die Ellipse ... erzeugt der Python-Interpreter als Fortsetzungsprompt, bei der “0” am Ende des Listings handelt es sich um der Rückgabewert der Funktion os.system().

TIPP

Finden Sie Python im interaktiven Modus zu spartanisch, werfen Sie doch einmal einen Blick auf den Python-Interpreter IPython [12].

Listing 1

$ python
Python 2.4.2 (#1, Oct  4 2005, 21:25:43)
[GCC 3.3.6 (Gentoo 3.3.6, ssp-3.3.6-1.0, pie-8.7.8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print "Hallo Welt!"
Hallo Welt!
>>> for i in range(5):print i, # Einrueckung ist wichtig
…
0 1 2 3 4
>>> import os
>>> os.system("ls -l")
total 8
-rw-r--r-- 1 schwa schwa 1927 Apr  7 11:57 gliederung.otl
-rw-r--r-- 1 schwa schwa 3667 Apr 12 22:04 teil1.lmtxt
0

Wenn Sie möchten, können Sie den Python-Code auch in eine Textdatei (üblichweise mit Endung .py) schreiben und diese mit python datei.py ausführen. Alternativ geben Sie den Pfad zum Interpreter in der ersten Zeile der Datei an, machden sie mit chmod a+x datei.py ausführbar machen und starten das Skript mit Pfad/meine_datei.py.

Falls Sie in der Datei Umlaute oder andere Zeichen außerhalb des ASCII-Zeichensatzes verwenden, erhalten Sie eine Fehlermeldung. Geben Sie in einem solchen Fall zusätzlich das Encoding der Datei an:

#!/usr/bin/python
# encoding: iso-8859-1

Bezeichner

In Python dürfen die Namen für Variablen, Funktionen, Klassen etc. beliebig viele Groß- und Kleinbuchstaben, Ziffern und Unterstriche enthalten, jdeoch nicht mit einer Ziffer anfangen. Groß/Kleinschreibung ist signifikant, Hallo und hallo bezeichnen also unterschiedliche Objekte. Der Python Style Guide [13] gibt Ratschläge, wie Sie Ihre Bezeichner benennen sollten.

Einfache Datentypen

Python kann mit einer ganzen Reihe von eingebauten Datentypen umgehen. Dazu zählen unter anderem:

  • Zahlen (int, long, float, complex)
  • Boolesche Variablen (bool)
  • Zeichenketten (str, unicode; siehe auch Kasten “Bytefolgen und Zeichenketten”)
  • Listen (list)
  • Tupel (tuple)
  • Dictionaries (dict, auch als “assoziatives Array” oder “Hash” bekannt)
  • Funktionen, Klassen, Methoden
  • Dateien
  • Module

Bytefolgen und Zeichenketten

Um Zeichenketten in einer Datei zu speichern oder über eine Netzverbindung zu übertragen, muss man sie als Bytefolgen darstellen. Früher entsprach dabei ein Zeichen genau einem Byte. Der ASCII-Code stellt ein “A” durch ein Byte mit dem Wert 65 dar. Er verwendet sieben Bit pro Zeichen und kann unter anderem keine Umlaute darstellen.

Daher wurden schon bald verschiedene Erweiterungen des ASCII-Codes entwickelt, die mit acht Bit maximal 256 verschiedene Zeichen darstellen. Im deutschsprachigen Raum kommen gern die ASCII-Erweiterungen ISO-8859-1 (Latin 1) und ISO-8859-15 (Latin 9) zum Einsatz.

Um mehr als 256 Zeichen als Bytefolge darzustellen, benötigt man andere Zeichenkodierungen, die gewöhnlich auf Unicode basieren. Unicode ordnet genauso wie ASCII jedem Zeichen einen Zahlenwert zu, allerdings definiert Unicode weitaus mehr Zeichen. Um diese Zahlenwerte in Bytefolgen umzusetzen, gibt es verschiedene “Übersetzungsvorschriften”, auch als Encodings bekannt. Das bei uns bekannteste Encoding, das mehr als acht Bit pro Zeichen verwenden kann, ist UTF-8.

In Python werden Bytefolgen durch den Typ str repräsentiert, Zeichenketten durch den Typ unicode. Viele ältere Python-Programme (und viele Beispiele in dieser Artikelreihe) verwenden str der Einfachheit halber auch für Zeichenketten, sind damit aber auf Encodings mit acht Bit pro Zeichen festgelegt.

Bei bekanntem Encoding können Zeichenketten in Bytefolgen umgewandelt werden – sofern sich jedes Zeichen in dem verwendeten Encoding überhaupt darstellen lässt. Ein Unicode-String mit chinesischen Schriftzeichen lässt sich beispielsweise nicht in ISO-8859-1 umsetzen.

Das folgende Listing zeigt den Umgang mit Unicode-Zeichenketten und Bytefolgen in Python.

#! /usr/bin/env python
# encoding: ISO-8859-1
# Encoding der Datei muss mit dem oben angegebenen übereinstimmen
unicode_string = u"Umlaute: äöü"
# Default-Encoding ist ASCII
try:
    # versucht implizit unicode_string.encode("ASCII")
    print unicode_string
except UnicodeEncodeError:
    print "Default ist ASCII - kann keine Umlaute ausgeben!"
# Ausgabe funktioniert mit explizitem Encoding (s. zweite Zeile)
print unicode_string.encode("ISO-8859-1")
# Encoding unterscheidet sich von dem des Terminals
print unicode_string.encode("UTF-8")

Das try/except-Konstrukt ignorieren Sie bitte vorerst, es wird in einer späteren Folge der Serie erklärt. Das Skript erzeugt auf einem Terminal mit ISO-8859-Kodierung folgende Ausgabe:

Default ist ASCII - kann keine Umlaute ausgeben!
Umlaute: äöü
Umlaute: äöü

Ist ihr Terminal dagegen auf UTF-8 eingestellt, erscheinen in der zweiten Zeile seltsame Zeichen, während in der dritten die Umlaute korrekt dargestellt werden.

Eine ausführliche Erklärung zum Thema Unicode und Bytestrings finden Sie in der Python-Unicode-FAQ [17].

In Klammern ist angegeben, unter welchem Namen Python die betreffenden Datentypen kennt. Der Typ long steht für ganze Zahlen mit beliebig vielen Stellen. Listing 2 zeigt einige Experimente im Interpreter mit den einfachen Datentypen Zahlen und Zeichenketten.

Listing 2

>>> print 1+3, type(4)
4 <type 'int'>
>>> print 11 20, type(11 20)
672749994932560009201 <type 'long'>
>>> print str(4), \type(str(4))
4 <type 'str'>
>>> print 'a'+"b", 3*"cd", \type("abc")
ab cdcdcd <type 'str'>
>>> 'a'+"b", 3*"cd", type("abc")
('ab', 'cdcdcd', <type 'str'>)
>>> # Vorsicht beiGanzzahl-Divisionenprint 1/3, 1./3, float(1)/3
0 0.333333333333 0.333333333333

Wie Sie sehen, erhalten Sie hier eine etwas andere Ausgabe, wenn Sie den print-Befehl weglassen (was nur im interaktiven Modus klappt – in Python-Dateien brauchen Sie explizite Ausgabeanweisungen). Dadurch bekommen Sie eine Darstellung, die sich stärker an die interne Repräsentation anlehnt. Insbesondere können Sie so Zahlen und Zeichenketten leicht voneinander unterscheiden:

>>> 4
4
>>> "4"
'4'

Zeichenketten können Sie in einfache oder doppelte Anführungszeichen einschließen. Gültige Python-Strings wären etwa: "Wie geht's?" und 'ein Artikel in "LinuxUser"'. Längere, vor allem mehrzeilige Zeichenketten lassen sich als so genannte Triple-quoted strings in paarweise passende """ und ''' einschließen:

"""Eine mehrzeile Zeichen-
kette, die Anführungszeichen
enthält: "'"""

Listen und Tupel

Listen enthalten eine Folge mehrerer beliebiger Python-Objekte, wie Listing 3 zeigt. Tupel sind Listen sehr ähnlich, lassen sich aber nach der Definition nicht mehr verändern (Listing 4). Beachten Sie, dass Tupel mit nur einem Element mit einem Komma vor der schließenden Klammer geschrieben werden, um sie von Ausdrücken zu unterscheiden.

Listing 3

>>> [] # leere Liste
[]
>>> [1, "abc"] # zwei Elemente
[1, 'abc']
>>> [1, # auf zwei Zeilen"abc"]
>>> # verschachtelte ListeL = [1, "abc", [5, 7]]
>>> # IndizierungL[0], L[1], L[2], L[2][0]
(1, 'abc', [5, 7], 5)

Listing 4

>>> T = () # leeres Tupel
>>> T = (1,) # ein Element
>>> T = (1, "abc") # 2 Elemente
>>> T[0] = 2 # Änderungsversuch
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: object does not support item assignment
>>> T
(1, 'abc')

Durch das implizite Entpacken von Tupeln (“Tuple unpacking”) lassen sich Werte vertauschen:

>>> a = 1; b = 2 # 2 Anweisungen
>>> a, b
(1, 2)
>>> b, a = a, b # vertauschen
>>> a, b
(2, 1)

Es gibt aber noch zahlreiche weitere Anwendungen. Mit so genannten Slices bilden Sie Teilsequenzen aus Zeichenketten, Listen und Tupeln. Listen lassen sich auf diese Art auch verändern, Zeichenketten und Tupel nicht.

>>> s = "Python"
>>> s[1:3], s[:3], s[2:], \s[-1], s[-2:]
('yt', 'Pyt', 'thon', 'n', 'on')
>>> L = [1, 2, 3, 4]
>>> L[1:3] = [7, 8, 9]
>>> L
[1, 7, 8, 9, 4]

Negative Indizes zählen dabei vom Ende der Sequenz. Bei der Zuweisung an einen Slice muss die rechte Liste nicht dieselbe Länge haben wie der Slice auf der linken Seite, wie das letzte Beispiel demonstriert.

Beachten Sie, dass das letzte Zeichen in s[1:3] nicht etwa s[3] ist, sondern s[2]. Faustregel: Der extrahierte String ist immer so lang wie die Differenz der oberen und der unteren Slice-Grenze.

Dictionaries

Dictionaries speichern Schlüssel/Wert-Paare und kommen zum Einsatz, wenn man anhand eines Wertes einen anderen “nachschlagen” will (Listing 5). Jeder Schlüssel muss unveränderlich (“immutable”) sein – was auf Zahlen, Zeichenketten und Tupel, nicht aber auf Listen und Dictionaries zutrifft.

Listing 5

>>> D = {'operating_system': "Linux", 'kernel': "0.8.15"}
>>> # alternative Schreibweise,# wenn die Schlüssel gültige# Python-Bezeichner sindD = dict(operating_system= "Linux", kernel="0.8.15")
>>> D
{'kernel': '0.8.15', 'operating_system': 'Linux'}
>>> print "Hier ist", \D['operating_system'], \D['kernel']
Hier ist Linux 0.8.15
>>> D['kernel'] = "0.8.17"
>>> print "Hier ist", \D['operating_system'], \D['kernel']
Hier ist Linux 0.8.17

Wie Sie an den Ausgaben der Dictionaries in Listing 5 sehen, haben die Einträge keine feste Reihenfolge! Sie können daher ein Dictionary nicht sortieren – die Einträge lassen sich aber gemäß einer bestimmten Sortierung der Schlüssel respektivre Werte ausgeben oder in eine Liste konvertieren.)

Sie können Werte in Zeichenketten einsetzen, indem Sie die einzusetzenden Werte als Tupel oder als Dictionary angeben (Listing 6).

Listing 6

>>> "Hier ist %s %s." % \("Linux", "0.8.15")
'Hier ist Linux 0.8.15.'
>>> D = {'operating_system': "Linux", 'kernel': "0.8.15"}
>>> "Hier ist %(operating_system)s %(kernel)s." % D
'Hier ist Linux 0.8.15.'

Die Python Library Reference führt auf, welche Platzhalter sich in einer Zeichenkette auf der linken Seite verwenden lassen [14]. Fließkommazahlen kann man beispielsweise rechtsbündig mit drei Nachkommastellen in einem zehn Zeichen breiten Feld darstellen: "%10.3f" % 7.1 ergibt die Zeichenkette " 7.100".

Zeichenketten, Listen, Tupel und Dictionaries besitzen verschiedene Methoden. Einige Beispiele führt die Tabelle “Wichtige Methoden” auf. Als Besonderheit ist zu erwähnen, dass die Länge dieser Objekte mit der Funktion len(objekt) (bei Dictionaries die Anzahl der Schlüssel-Wert-Paare) und nicht mit einer Methode ermittelt wird.

Etliche weitere Methoden listet die Python Library Reference auf [15]. Methoden von Listen und Dictionaries verändern oft den Wert des Objekts; als Rückgabewert erhält man dann nicht das veränderte Objekt, sondern den besondere Wert None!

Wichtige Methoden

Methode Anwendung Ergebnis
Zeichenketten
startswith() "Python".startswith("Py") True
encode(encoding) Unicodestring.encode("utf-8") Bytestring
decode(encoding) Bytestring.decode("utf-8") Unicode-String
lower() "Python".lower() "python"
replace(Vorher, Nachher) "abc defab"".replace("ab", "xyz") "xyzc defxyz"
split() "teil1 teil2".split() ['teil1', 'teil2']
split(Trenner) "Python-Artikel".split("-") ['Python', 'Artikel']
join(Liste) "-".join("a", "b", "c") "a-b-c"
Listen
append(Element) L=[1]; L.append(2) None (L=[1, 2])
extend(Elemente) L=[1]; L.extend([2, 3]) None (L=[1, 2, 3])
sort() L=[3, 1, 2]; L.sort() None (L=[1, 2, 3])
sort(key=Funktion) L=['B', 'a']; L.sort(key=string.lower) None (L=['a', 'B'])
Dictionaries
keys() {1: "a", 2: "b"}.keys() [1, 2] oder [2, 1]
values() {1: "a", 2: "b"}.values() ["a", "b"] oder ["b", "a"]
has_key(Key) {1: "a", 2: "b"}.has_key(2) True
update(D2) D={1: "a"}; D.update({2: "b"}) None (D={1: "a", 2: "b"})

Operatoren

Sie können die eingebauten Datentypen mit verschiedenen Operatoren bearbeiten. Zahlen unterstützen die üblichen arithmetischen Operationen mit den geläufigen Prioritäten (Potenzierung erfolgt vor Multiplikation und Division ausgeführt, diese wiederum vor Addition und Subtraktion). Eine Liste der unterstützen Operatoren findet sich in der Python Reference Library [15].

Zeichenketten lassen sich ebenso wie Listen und Tupel addieren und mit ganzen Zahlen multiplizieren. Dabei entstehen neue Objekte; die Operanden bleiben unverändert (Listing 7).

Listing 7

>>> "abc" + "def"
'abcdef'
>>> 10 * "=-"
'=-=-=-=-=-=-=-=-=-=-'
>>> (1, 2) + (3, 4)
(1, 2, 3, 4)
>>> (1, 2) * 3
(1, 2, 1, 2, 1, 2)
>>> [1, 2] + [3, 4]
[1, 2, 3, 4]
>>> 3 * [1, 2]
[1, 2, 1, 2, 1, 2]

Additionen sollte man vermeiden, wenn sie sehr häufig – etwa in einer Schleife mit vielen Durchläufen – erfolgen. Zeichenketten erzeugt man in diesem Fall besser, indem man die Teilstücke in einer Liste sammelt und später mit der join-Methode verbindet. Listen erweitert man mit der append– oder extend-Methode, wobei die ursprüngliche Liste verändert wird.

Im Gegensatz zu vielen anderen Sprachen sind Zuweisungen in Python keine Operatoren, sondern Anweisungen. Für die Praxis bedeutet das, dass Sie keine Zuweisungen in Bedingungen von if– oder while-Anweisungen verwenden können. Das umgeht eine beliebte Fehlerquelle einiger anderer Programmiersprachen.

Zuweisungen – ohne Variablen

Bei der Zuweisung gibt es in Python eine Besonderheit: Es gibt keine Variablen – jedenfalls nicht in dem Sinn, dass eine Variable ein Objekt “enthält”. Beim Umgang mit unveränderlichen Typen wie Zahlen oder Zeichenketten fällt das allerdings nicht auf:

>>> n1 = 1; n2 = n1
>>> print n1, n2
1 1
>>> n2 = 3
>>> print n1, n2
1 3

Umso deutlicher jedoch tritt dieser Umstand bei Modifikationen an veränderlichen Typen wie Listen oder Dictionaries zutage:

>>> L1 = [1, 2]
>>> L2 = L1
>>> print L1, L2
[1, 2] [1, 2]
>>> L2[0] = 3
>>> print L1, L2
[3, 2] [3, 2]

Obwohl Sie scheinbar nur die Liste L2 verändert haben, macht sich die Änderung auch bei der Ausgabe von L1 bemerkbar. Tatsächlich wird die Liste [1, 2] nicht kopiert, sondern nur durch einen weiteren Namen (L2) referenziert.

Im Zusammenhang mit Zahlen passiert das ebenfalls. Da bei der Zuweisung n2 = 3 im ersten Beispiel die ursprüngliche Bindung an das Objekt 1 gelöst wird, sticht das aber nicht ins Auge. Hier wurde also die Bindung verändert. Im Listen-Beispiel dagegen wurde referenzierte Objekt selbst modifiziert (was bei unveränderlichen Objekten wie Zahlen oder Zeichenketten definitionsgemäß gar nicht möglich ist).

Abbildung 2 zeigt links (von oben nach unten) die Vorgänge bei den obigen Ganzzahl-Zuweisungen, rechts die bei den Listen-Zuweisungen.

Abbildung 2: Beispiele für Zuweisungen in Python. Die Python-Anweisungen sind in blauer Schrift dargestellt; Pfeile weisen von Namen zu Objekten. Gelöschte Referenzen und Werte sind rot durchgestrichen.

Abbildung 2: Beispiele für Zuweisungen in Python. Die Python-Anweisungen sind in blauer Schrift dargestellt; Pfeile weisen von Namen zu Objekten. Gelöschte Referenzen und Werte sind rot durchgestrichen.

Was auf den ersten Blick exotisch wirkt, folgt einer einfachen Grundregel: Python kopiert keine Daten, außer wenn Sie das explizit verlangen. Diese Regel hat einen Sinn: Während sich Zahlen und Zeichenketten noch relativ einfach kopieren lassen, wird es bei komplexeren Typen knifflig. Wie soll man eine geöffnete Datei oder eine Internetverbindung (Socket) kopieren? Python versucht hier nicht, “intelligent zu raten”, sondern überlässt dem Programmierer die Definition, was genau “Kopieren” für einen bestimmten Datentyp bedeutet. Ob Sie es glauben oder nicht: Das standardmäßige Verhalten von Python ist fast immer nützlich.

Falls es ausnahmsweise nötig wird, erzeugen Sie von Listen oder Dictionaries relativ leicht so genannte flache Kopien (“shallow copies”, nur eine “Ebene” tief). Ein Beispiel zeigt Listing 8.

Listing 8

>>> L1 = [1, 2]
>>> L2 = L1[:]
>>> print L1, L2
[1, 2] [1, 2]
>>> L2[0] = 3 # L1 wird nicht verändert
>>> print L1, L2
[1, 2] [3, 2]

Die erste Zeile des Listing 8 bindet das Objekt [1, 2] an den Namen L1 gebunden. Mit L1[:] (seltener verwendet: list(L1)) entsteht danach eine flache Kopie. Bei der Zuweisung L2[0] = 3 ändert sich L1 nicht.

Sollten Sie doch einmal eine “tiefe” Kopie benötigen, können Sie das Modul copy[16] bemühen. Listing 9 erzeugt die Kopie eines Dictionaries mit der copy-Methode.

Listing 9

>>> D1 = {1: "a", 2: "b"}
>>> D2 = D1.copy()
>>> D2[1] = "c"
>>> print D1, D2
{1: 'a', 2: 'b'} {1: 'c', 2: 'b'}

Bedingte Codeausführung

Zur Ablaufsteuerung von Programmen bietet Python alle geläufigen Kontrollstrukturen an. Die if-Anweisung für Fallunterscheidungen beispielsweise sieht in Python so aus:

if bedingung1:
    anweisungen1
elif bedindung2:
    anweisungen2
else:
    anweisungen3

Falls der Ausdruck bedingung1 “wahr” ist, werden die anweisungen1 (es kann natürlich auch eine einzelne Anweisung sein) ausgeführt und das if-Konstrukt nicht weiter ausgewertet.

Als “falsch” zählen numerische Null-Werte (0, 0L, 0.0, 0.0+0.0j), der boolschen Wert False, leere Zeichenketten, leere Listen, leere Tupel, leere Dictionaries sowie der spezielle Wert None. Alle anderen Werte betrachtet Python als “wahr”. Benutzerdefinierte Objekte (sie kommen in einer späteren Folge zur Sprache) “entscheiden” selbst, wann sie “wahr” oder “falsch” sind.

Ist bedingung1 falsch, aber bedingung2 wahr, werden die anweisungen2 ausgeführt. Trifft keine der vorherigen Bedingungen zu, kommen die anweisungen3 im else-Zweig zur Ausführung. Mehrere elif-Zweige sind möglich, elif und/oder else-Zweig dürfen aber auch fehlen.

Bedingungsausdrücke brauchen Sie nicht einzuklammern; nach den Bedingungen und nach else muss vielmehr ein Doppelpunkt stehen. Numerische Vergleiche lassen sich bei Bedarf zusammenfassen, wie in if 1 <= x < 2:.

Richtig eingerückt

Anweisungsblöcke schließt man in Python nicht wie in vielen anderen Sprachen in geschweifte Klammern oder Schlüsselwörter ein. Stattdessen erkennt Python an der Einrückung der Anweisungen, welche zu einem Block gehören. Das gilt nicht nur für if-Anweisungen, sondern generell, also auch bei Schleifen- oder Funktionsrümpfen.

Der Hintergrund dieses Ansatzes ist, dass Code ohnehin eingerückt werden sollte, um die Struktur zu verdeutlichen und den Code lesbarer zu machen. Ein angenehmer Nebeneffekt der Python-Methode: Sie macht Blockbegrenzer überflüssig und den Code etwas kürzer und übersichtlicher. Außerdem beseitigt diese Vorgehensweise potenzielle Quellen für Fehler und Missverständnisse, wie sie in C vorkommen – etwa, wenn zwei aufeinander folgende Anweisungen eingerückt sind, aber die geschweiften Klammern fehlen.

Durch einen Backslash am Zeilenende oder noch nicht abgeschlossene Teilausdrücke (Klammerung) erkennt Python, dass sich eine Anweisung über die Zeilengrenze hinweg fortsetzt. Hier ein konkretes Beispiel für Anweisungsblöcke:

if x > 1:
    print "x größer als 1"
    groesser()
elif x == 1:
    print "x gleich 1"
    gleich()
else:
    print "x kleiner als 1"
    kleiner()

Hier gehören print "x größer als 1" und der Funktionsaufruf groesser() zu einem Block und werden nacheinander ausgeführt, falls x größer als Eins ist. Der Python Style Guide [13] empfiehlt, pro Einrückungsebene vier Leerzeichen zu verwenden; Programmiereditoren tun das normalerweise automatisch oder lassen sich entsprechend konfigurieren.

Ab der kommenden Python-Version 2.5 soll es auch eine Fallunterscheidung in Form eines Ausdrucks geben, ähnlich dem ternären Operator ?: in C. Dabei weicht aber die Reihenfolge der Operanden von der C-Notation ab:

x = Falls_wahr if Bedingung else Falls_falsch

Jetzt geht’s rund

Python kennt sowohl while– als auch for-Schleifen. Ein Beispiel für eine while-Schleife:

summe = 0.0
while True:
  eingabe = raw_input(
            "Zahlenwert: ")
  if eingabe == "ende":
      print "Summe =", summe
      break
  # eingabe explizit in
  # Fließkommazahl wandeln
  summe = summe + float(eingabe)

Wie Sie sehen, lässt sich die Schleife mit break verlassen. Die Anweisung continue ermöglicht, den aktuellen Schleifendurchlauf abzubrechen und den nächsten zu starten (falls die while-Bedingung noch zutrifft). Beide Schlüsselwörter sind auch in for-Schleifen möglich.

Die for-Schleife iteriert stets über Sequenzen (genauer: Iteratoren, dazu in einer späteren Folge mehr). Hier ein Beispiel:

for a, b in [(1, 2), [3, "abc"],
             ("x", 7)]:
    print a, b

Hier sehen Sie wieder das automatische “Entpacken” von Tupeln mit impliziten Zuweisungen an a und b, wobei der “entpackte” Wert wie beim zweiten Listenelement auch eine Liste sein darf. Normalerweise nicht zu empfehlen ist diese Variante, die explizit den Listenindex verwendet:

L = [(1, 2), [3, "abc"],
     ("x", 7)]
for i in range(len(L)):
    print L[i][0], L[i][1]

Diese Variante ist nicht nur umständlicher als der erste Ansatz, sondern auch wesentlich fehleranfälliger.

Die for-Anweisung setzt nicht voraus, dass die zu durchlaufenden Werte nach dem Schlüsselwort in schon zu Beginn der Schleife bekannt sind. Der folgende Code öffnet die Datei “text” und zählt, in wie vielen Zeilen das Wort “Python” (ungeachtet der Schreibweise) vorkommt. Dabei liest der Code bei jedem Schleifendurchlauf eine neue Zeile aus der Datei, bis er sie komplett verarbeitet hat. Dadurch müssen nicht alle Zeilen auf einmal in den Speicher geladen werden müssen, was bei großen Dateien ungünstig wäre.

datei = open("text")
zeilenzahl = 0
for zeile in datei:
    if "python" in zeile.lower():
        zeilenzahl += 1
datei.close()
print 'Vorkommnisse von "python":', zeilenzahl

Bei dem Dateiobjekt handelt es sich um einen so genannter Iterator. Der Vorteil von Iteratoren ist, dass sie “unendlich” sein können. Zum Beispiel kann man einen Iterator schreiben, der bei jedem Schleifendurchlauf die nächste ganze Zahl liefert, bis die Schleife mit break verlassen wird.

Ein Sonderfall von Schleifen und Fallunterscheidungen findet sich bei den “List Comprehensions”. Hier lassen sich mehrere for-Konstrukte verschachteln; der if-Teil darf fehlen. Das folgende Beispiel erzeugt eine Liste mit den Quadraten der ganzen Zahlen von 0 bis 10:

>>> [x 2 for x in range(10+1)if x % 2 == 0]
[0, 4, 16, 36, 64, 100]

Damit die durch range erzeugte Liste auch die 10 enthält, muss das Argument 11 sein – analog zur Verwendung des zweiten Index in Slices. x % 2 liefert den Rest der Ganzzahldivision von x und 2. Bei geraden Zahlen ist dieser Rest 0 und damit die Bedingung falsch. Daher muss sie durch den Vergleich mit 0 wahr werden, weil uns ja gerade die Quadrate der geraden Zahlen interessieren.

Übrigens geht es noch etwas einfacher, wenn wir range ein Argument für die Schrittweite mitgeben (der kleinste Wert der Liste, 0, muss dann ebenfalls angegeben werden):

>>> [x 2for x in range(0, 10+1, 2)]
[0, 4, 16, 36, 64, 100]

Ausblick

Im nächsten Heft erfahren Sie, wie Sie Funktionen in Python verwenden und wie Sie zusammengehörige Funktionen in eigenen Modulen gruppieren.

Glossar

Encoding

Das Encoding gibt an, durch welche Bytefolgen Zeichen ausgedrückt werden. Bekannte Encodings sind ASCII, ISO-8859-1 (Latin 1) und UTF-8. Bei ASCII und ISO-8859-1 wird jedes Zeichen durch genau ein Byte dargestellt, bei UTF-8 durch bis zu vier Byte pro Zeichen. Das erhöht die Menge der darstellbaren Zeichen.

Infos

[1] Python-Homepage: http://www.python.org/

[2] Python-Online-Dokumentation: http://www.python.org/doc/

[3] Python-Referenz: http://www.limsi.fr/Individu/pointal/python/pqrc/versions/PQRC-2.4-A4-latest.pdf

[4] Parser-Generatoren: http://wiki.python.org/moin/LanguageParsing

[5] Spieleprogrammierung mit pygame: http://www.pygame.org/

[6] PDF-Erzeugung mit Reportlab: http://www.reportlab.org/rl_toolkit.html

[7] Tkinter: http://wiki.python.org/moin/TkInter

[8] PyGTK: http://wiki.python.org/moin/PyGtk

[9] wxPython: http://www.wxpython.org/

[10] PyQt: http://wiki.python.org/moin/PyQt

[11] Python Package Index (PyPI): http://www.python.org/pypi

[12] IPython: http://ipython.scipy.org/

[13] Python Style Guide: http://www.python.org/dev/peps/pep-0008/

[14] Zeichenketten-Ersetzung: http://docs.python.org/lib/typesseq-strings.html

[15] Methoden für eingebaute Datentypen: http://docs.python.org/lib/types.html

[16] copy-Modul: http://docs.python.org/lib/module-copy.html

[17] Python-Unicode-FAQ: http://p-nand-q.com/python/unicode_faq.html

Der Autor

Dr.-Ing. Stefan Schwarzer verwendet Python seit sechs Jahren und hat zum Thema das Buch “Workshop Python” veröffentlicht. Der selbstständige Softwareentwickler ist unter mailto:sschwarzer@sschwarzer.net zu erreichen.

LinuxUser 09/2006 KAUFEN
EINZELNE AUSGABE
ABONNEMENTS
TABLET & SMARTPHONE APPS
E-Mail Benachrichtigung
Benachrichtige mich zu:

Hinweis: Dieser Artikel ist älter als ein Jahr, enthaltene Informationen sind möglicherweise veraltet.

0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben