Python/Kontrollstrukturen

Aus Mikiwiki
< Python
Version vom 17. Januar 2009, 19:27 Uhr von Michi (Diskussion | Beiträge) (Die Seite wurde neu angelegt: Der Rumpf einer Schleife wird eingerückt: die Einrückung ist Pythons Art, Anweisungen zu gruppieren. Python stellt (noch) keine intelligenten Mechanismen zum Bearbei...)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche

Der Rumpf einer Schleife wird eingerückt: die Einrückung ist Pythons Art, Anweisungen zu gruppieren. Python stellt (noch) keine intelligenten Mechanismen zum Bearbeiten von Eingabezeilen zur Verfügung, sodass die Tabulatortaste oder das Leerzeichen für jede eingerückte Zeile eingegeben werden muss. Üblicherweise werden anspruchsvolle Eingaben für Python mit einem Text-Editor eingegeben, von denen die meisten eine automatische Einrückung bieten. Wird eine zusammengesetzte Anweisung interaktiv eingegeben, so muss sie durch eine Leerzeile abgeschlossen werden, um das Ende anzuzeigen (da der Parser nicht raten kann, wann die letzte Zeile eingegeben wurde). Alle Zeilen eines Blocks müssen um den gleichen Betrag eingerückt werden!

Vergleichsoperatoren

Die Vergleichsoperatoren werden wie in C geschrieben.

< Kleiner als
> Grösser als
== Gleich
<= Kleiner gleich
>= Grösser gleich
!= Nicht gleich

Anweisung "if"

In einer "if"-Anweisung kann es keine oder mehrere "elif"-Teile geben, der "else"-Teil ist optional. Das Schlüsselwort "elif" ist eine Kurzschreibweise für "else if" und nützlich, um exzessive Einrückungen zu vermeiden. Eine Sequenz der Art "if ... elif ... elif ..." ist ein Ersatz für die Anweisungen "switch" oder "case" in anderen Programmiersprachen.

>>> x = int(raw_input("Bitte geben Sie eine Zahl ein: "))
Bitte geben Sie eine Zahl ein: 23
>>> if x < 0:
...     x = 0
...     print 'Negative changed to zero'
... elif x == 0:
...     print 'Zero'
... elif x == 1:
...     print 'Single'
... else:
...     print 'More'
...
More

Anweisung "for"

In Python unterscheidet sich die "for"-Anweisung davon, was sie in C oder Pascal bewirkt. Statt stets über eine arithmetische Folge von Zahlen zu iterieren (wie in Pascal) oder dem Benutzer die Möglichkeit zu geben, die Schrittweite und Endbedingung der Iteration zu definieren (wie in C), iteriert die "for"-Anweisung in Python über die Elemente einer Sequenz (z. B. einer Liste oder einer Zeichenkette) in der Reihenfolge ihres Auftretens in dieser Sequenz.

>>> a = ['cat', 'window', 'defenestrate'] # Messe einige Zeichenketten
>>> for x in a:
...     print x, len(x)
...
cat 3
window 6
defenestrate 12

Es ist nicht sicher, die Sequenz zu verändern, über die gerade iteriert wird (das kann nur mit veränderlichen Sequenztypen passieren, z. B. Listen). Wenn die Liste verändert werden muss, über die iteriert wird, z. B. um die einzelnen Elemente zu kopieren, so muss über eine Kopie iteriert werden. Mit der Teilbereichs-Notation ist dies sehr bequem.

>>> for x in a[:]: # Erstelle eine Teilbereichs-Kopie der ganzen Liste
...     if len(x) > 6: a.insert(0, x)
...
>>> a
['defenestrate', 'cat', 'window', 'defenestrate']

Anweisung "while"

Die "while"-Schleife wird durchlaufen, solange die Bedingung (hier: b < 10) wahr bleibt. In Python ist (wie in C), jede nicht-negative ganze Zahl wahr; Null ist falsch. Die Bedingung darf auch eine Zeichenkette oder eine Liste oder jede beliebige Sequenz sein; alles mit einer Länge verschieden von Null ist wahr, leere Sequenzen sind falsch.

>>> a, b = 0, 1 # Fibonacci-Reihe: Die Summe zweier Elemente ergibt das n
>>> while b < 10:
...     print b
...     a, b = b, a+b
...
1
1
2
3
5
8

Anweisung "print"

Die "print"-Anweisung gibt den Wert (oder die Werte) des Ausdrucks (oder der Ausdrücke) aus, den (oder die) es bekommt. Sie unterscheidet sich von der Ausgabe eines reinen Ausdrucks in der Art wie Mehrfach-Ausdrücke und Zeichenketten behandelt werden. Zeichenketten werden ohne Anführungszeichen ausgegeben und es wird ein Leerzeichen zwischen die Elemente gesetzt, damit eine gut lesbare Formatierung entsteht.

>>> i = 128*128
>>> print 'Der Wert von i ist', i
Der Wert von i ist 16384

Ein Komma am Zeilenende verhindert nach der Ausgabe den Sprung in die neue Zeile.

>>> a, b = 0, 1
>>> while b < 1000:
...     print b,
...     a, b = b, a+b
...
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

Falls die letzte Zeile nicht leer war, fügt der Interpreter eine neue Zeile ein, bevor er den nächsten Prompt ausgibt.

Funktion "range()"

Die Funktion "range()" erzeugt Listen, die arithmetischen Aufzählungen entsprechen. Der angegebene Endpunkt (hier "10") ist nie Teil der erzeugten Liste, da "range()" die Werte nach den mit 0 beginnenden gültigen Indizes erzeugt.

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Der zu erzeugende Bereich kann mit einer beliebigen Zahl beginnen und es kann auch eine andere ganzzahlige Schrittweite angegeben werden (sogar eine negative).

>>> range(5, 10)
[5, 6, 7, 8, 9]
>>> range(0, 10, 3)
[0, 3, 6, 9]
>>> range(-10, -100, -30)
[-10, -40, -70]

Zum Durchlaufen der Indizes einer Sequenz können die Funbktionen "range()" und "len()" kombiniert werden.

>>> a = ['Hänschen','klein','ging','allein']
>>> for i in range(len(a)):
...     print i, a[i]
...
0 Hänschen
1 klein
2 ging
3 allein

Anweisungen "break" und "continue", "else"-Klauseln in Schleifen

Die Anweisung "break" bricht (wie in C) aus der kleinsten umgebenden "for"- oder "while"-Schleife aus.

Die Anweisung "continue" setzt (wie in C) die Schleife mit der nächsten Iteration fort.

Schleifen-Anweisungen dürfen eine "else"-Klausel haben. Sie wird ausgeführt, wenn die Schleife vollständig durch die Liste gelaufen ist (mit "for") oder wenn die Bedingung falsch wird (mit "while"), aber nicht, wenn die Schleife durch die Anweisung "break" beendet wird. Folgende Schleife sucht nach Primzahlen.

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print n, 'entspricht', x, '*', n/x
...             break
...     else:
...         print n, 'ist eine Primzahl'
...
2 ist eine Primzahl
3 ist eine Primzahl
4 entspricht 2 * 2
5 ist eine Primzahl
6 entspricht 2 * 3
7 ist eine Primzahl
8 entspricht 2 * 4
9 entspricht 3 * 3

Anweisung "pass"

Die Anweisung "pass" tut nichts. Sie kann benutzt werden, wenn eine Anweisung syntaktisch notwendig ist, ohne dass das Programm wirklich etwas tun muss.

>>> while 1:
...     pass # Aktives Warten auf eine Tastatur-Unterbrechung
...

Definition von Funktionen

Das Schlüsselwort "def" leitet die Definition einer Funktion ein. Danach müssen der Funktionsname, eine Liste von formalen Parametern in runden Klammern sowie ein Doppelpunkt folgen. Die Anweisungen, die den Rumpf der Funktion ausmachen, beginnen in der folgenden Zeile und müssen eingerückt sein. Die erste Anweisung des Rumpfes kann optional ein Zeichenketten-Literal sein. Dieses Zeichenketten-Literal ist die Dokumentations-Zeichenkette der Funktion, auch Docstring genannt. Es gibt Werkzeuge, die Docstrings verwenden, um automatisch online oder gedruckte Dokumentation zu erzeugen oder um den Benutzer interaktiv im Code stöbern zu lassen.

Folgende Funktion gibt die Fibonacci-Folge bis zu einer beliebigen Grenze aus.

>>> def fib(n): # Schreibe Fibonacci-Reihe bis n
...     "Gib Fibonacci-Reihe bis n aus."
...     a, b = 0, 1
...     while b < n:
...             print b,
...             a, b = b, a+b
...
>>> fib(2000) # Aufruf der eben definierten Funktion
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

Die Ausführung einer Funktion führt zu einer neuen Symboltabelle mit den lokalen Variablen dieser Funktion. Dabei speichern alle Variablenzuweisungen in einer Funktion den Wert in der lokalen Symboltabelle. Referenzen auf Variablen dagegen werden erst in der lokalen Symboltabelle gesucht, dann in der globalen Symboltabelle und schliesslich in der Tabelle der eingebauten Namen. Daher kann in einer Funktion globalen Variablen nicht direkt ein Wert zugewiesen werden (solange sie nicht in in einer global-Anweisung vorkommen), obwohl sie referenziert werden können.

Die eigentlichen Parameter (Argumente) eines Funktionsaufrufs werden dann in die lokale Symboltabelle der aufrufenden Funktion eingefügt, wenn die Funktion aufgerufen wird. Daher werden die Argumente mit Werte-Semantik (engl. call by value) übergeben (wobei der Wert immer eine Objekt-Referenz und nicht der Wert des Objektes ist).

Eine Funktionsdefinition trägt den Namen der Funktion in die aktuelle Symboltabelle ein. Der Wert des Funktionsnamens hat einen Typ, der vom Interpreter als eine benutzerdefinierte Funktion erkannt wird. Dieser Wert kann einem anderen Namen zugewiesen werden, der dann auch als Funktion verwendet werden kann. Dies kann als allgemeiner Mechanismus zur Umbenennung von Funktionen dienen.

>>> fib
<function fib at 0xb7dbd48c>
>>> f = fib
>>> f(100)
1 1 2 3 5 8 13 21 34 55 89

"fib" könnte anstatt als eine Funktion auch als eine Prozedur angesehen werden. Sowohl in Python wie in C sind Prozeduren bloss Funktionen, die keinen Wert zurück geben. Technisch gesehen geben Prozeduren zwar einen Wert zurück - dieser heisst "None" (ein eingebauter Name). Die Ausgabe des Wertes "None" wird aber üblicherweise vom Interpreter unterdrückt, falls es der einzige Ausgabewert ist. Bei Bedarf kann man ihn aber auch anzeigen lassen.

>>> print fib(0)
None

Anstatt die Fibonacci-Folge direkt auszudrucken, kann auch eine Funktion geschrieben werden, welche eine Liste von Zahlen der Fibonacci-Folge zurückgibt.

  • Die Anweisung "return" verlässt eine Prozedur mit der Rückgabe eines Wertes. "return" ohne einen Ausdruck als Argument gibt "None" zurück. Beim Erreichen des Endes einer Prozedur wird ebenfalls None zurückgegeben.
  • Die Anweisung "result.append(b)" ruft eine Methode des Listenobjektes "result" auf. Eine Methode ist eine Funktion, die zu einem Objekt "gehört" und "obj.methodname" heisst, wobei "obj" irgendein Objekt ist (z. B. auch ein Ausdruck), und "methodname" der Name einer Methode, die vom Objekttyp definiert wird. Verschiedene Typen definieren verschiedene Methoden. Methoden verschiedener Typen dürfen den gleichen Namen haben ohne dass eine Doppeldeutigkeit entstünde. (Es ist möglich, mit Hilfe von Klassen eigene Objekttypen und -methoden zu definieren.) Die Methode "append()" im Beispiel ist für Listenobjekte definiert. Sie fügt ein neues Element ans Ende einer Liste hinzu. Hier ist das gleichwertig zu "result = result + [b]", aber effizienter.
>>> def fib2(n): # Gib Fibonacci-Reihe bis n aus
...    "Gib eine Liste mit der Fibonacci-Reihe bis n zurueck."
...    result = []
...    a, b = 0, 1
...    while b < n:
...       result.append(b) # Siehe unten
...       a, b = b, a+b
...    return result
...
>>> f100 = fib2(100) # Rufe sie auf
>>> f100 # Gib das Ergebnis aus
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

Argumente mit Vorgabewerten

In einer Funktion kann auch ein Vorgabewert für eines oder mehrere Argumente bestimmt werden.

>>> def ask_ok(prompt, retries=4, complaint='ja oder nein, bitte!'):
...     while 1:
...             ok = raw_input(prompt)
...             if ok in ('j', 'J', 'Ja', 'ja'): return 1
...             if ok in ('n', 'N', 'Nein', 'nein'): return 0
...             retries = retries - 1
...             if retries < 0: raise IOError, 'refusenik user'
...             print complaint
...

Diese Funktion kann auf zwei Arten aufgerufen werden:

>>> ask_ok('Wollen Sie wirklich beenden?')
Wollen Sie wirklich beenden?j
1
>>> ask_ok('Wollen Sie wirklich beenden?')
Wollen Sie wirklich beenden?n
0
>>> ask_ok('Ist es OK, die Datei zu überschreiben?', 2)
Ist es OK, die Datei zu überschreiben?j
1
>>> ask_ok('Ist es OK, die Datei zu überschreiben?', 2)
Ist es OK, die Datei zu überschreiben?n
0

Die Vorgabewerte werden im definierenden Geltungsbereich zum Zeitpunkt der Funktionsdefinition ausgewertet. So gibt z. B. die folgende Funktion den Wert "5" aus.

>>> i = 5
>>> def f(arg = i): print arg
...
>>> i = 6
>>> f()
5

Ein Vorgabewert wird nur einmal ausgewertet. Das macht dann einen Unterschied, wenn es sich um ein veränderliches Objekt handelt, etwa eine Liste oder ein Wörterbuch. Die folgende Funktion sammelt die ihr übergebenen Argumente in aufeinander folgenden Aufrufen.

>>> def f(a, l = []):
...     l.append(a)
...     return l
...
>>> print f(1)
[1]
>>> print f(2)
[1, 2]
>>> print f(3)
[1, 2, 3]

Wenn aufeinander folgende Aufrufe sich das veränderliche Objekt nicht teilen sollen, kann dafür folgende Funktion verwendet werden.

>>> def f(a, l = None):
...     if l is None:
...             l = []
...     l.append(a)
...     return 1
...
>>> print f(1)
1