Python-Kurs für Programmierer
| Dozent: | Henning Hasemann |
|---|---|
| Datum: | 3. und 4. April 2006 |
1 Einleitung
Beautiful is better than ugly.
—The Zen of Python
1.1 Warum Python?
- Schnelle Entwicklung
- kurzer und gut lesbarer Code
- Eine Sprache für Web, cli und gui
- Plattformübergreifend
- Referenzen:
- Google (Prototyping)
- ILM
- NASA
- Gentoo- und Ubuntu Linux
1.2 Warum nicht Python?
- Nicht so verbreitet wie PHP, C, Java, etc...
- Code nicht so schnell und performant wie C oder C++
Es gibt mehrere Möglichkeiten, Performace-Problemen in Python-Code zu begegnen:
- Python's C-Api / C/C++-Interfacegenerator "swig"
- Ein sehr schneller JIT-Compiler: psyco
- Dialekte/Untermengen von Python die sich direkt zu C-Code und somit in schnelle binaries compilen lassen
1.3 Eigenschaften von Python
- OOP (ALLES ist ein objekt)
- Einrückung spielt eine Rolle!
- Interpretiert
- Hohes Level
- Strong, dynamic typing
- "Batteries included": Viele nützliche Module in der Standatddistribution verfügbar!
- C/C++ - Interface
- Java-Interpreter (jython) verfügbar
- Eingebauter Garbage Collector
1.4 Verwenden von Python
- Interpreter: python
- Interaktiver Modus: dir()
- Skriptmodus
- Hilfe zum Thema xyz: pydoc xyz, help("xyz")
- Editoren: scite, spe, ...
1.5 Versionen
- 2.3 ist derzeit am weitesten verbreitet.
- 2.4 ist stabil, 2.5 befindet sich in der Entwicklung und bringt z. B. die Möglichkeit, Daten an laufende Generatoren zu übergeben.
- Die Beispiele hier beziehen sich auf Python 2.3
1.6 Hallo Welt!
print "Hallo, Welt"
name = raw_input("Wie heißt du?")
print "Hallo", name, "!"- print gibt eine Komma-getrennte Liste von Werten (oder einen einzelnen) aus
- raw_input() fordert zur Eingabe eines Strings auf.
2 Einfache Datentypen
Explicit is better than implicit.
—The Zen of Python
2.1 Numerische Datentypen
Ganzzahlen: Integers/Longs
- Ints werden automatisch zu longs, wenn zu groß, daher Unterscheidung überflüssig.
- Longs können beliebig groß werden!
-5898798 3000 237498230984
Fließkommazahlen: Floats
Achtung: Rundungsfehler! (Es gibt aber Module für beliebig genaue Fließkommazahlen.)
3e-10 0.000056 -.9998
Fließkommazahlen unterliegen einer gewissen Ungenauigkeit, das liegt an ihrer internen Repräsentation. Das Modul decimal kann benutzt werden, um beliebig genaue Fließkommazahlen zu speichern.
Komplexe Zahlen
3.4 - 7.1j 4 + 2j
2.2 Stringliterale
- Normale und doppelte Anführungszeichen haben die selbe Funktion
- Der Backslash "\" kann zum quoten verwendet werden
- Mehrzeilige Strings werden mit """ oder ''' dargestellt.
a = "Die Gebühren werden \"ein bisschen\" erhöht.\nZumindest hieß es das." b = 'Die Gebühren werden "ein bisschen" erhöht.\nZumindest hieß es das.' c = """Die Gebühren werden "ein bisschen" erhöht. Zumindest hieß es das."""
2.3 Strings
Strings können das Null-Zeichen enthalten (!)
Strings sind immutabel!
"Rohe" Strings kann man mit r einleiten:
a = r"In rohen strings wird das \-Zeichen nicht interpretiert!"
Es gibt keinen Datentyp für einzelne Zeichen, statt dessen Strings der Länge 1.
Stringliterale werden automatisch verkettet:
a = "Dies ist ein Satz." 'Hier ist noch einer.'
2.4 Konvertierungen
Alle diese Datentypen haben Konstruktoren zur Erstellung eines Objekts:
>>> a = "500" >>> type(a) <type 'str'> >>> b = int(a) >>> b 500 >>> type(b) <type 'int'> >>> str(3.2) '3.2'
3 Grundsätzliche Syntax und Semantik
<Optonic> "$&$%/$%!&/(%( *kreisch* *ausflipp* <Feik> Optonic: Oh, Du kannst auch Perl? ;-)—fortune
3.1 Variablen
Funktionsweise ähnlich Referenzen
Strong Dynamic typing
dynamic typing: Ein und dieselbe Variable kann Objekte von jedem beliebigen Typ aufnehmen
In C ist dies zum Beispiel nicht der Fall, der Typ einer Variablen wird bei der Deklaration festgelegt. (Wenn man von der Sonderrolle der Zeiger, insbesondere void *, absieht)
strong typing: Der Typ eines Objekts ist durch das Objekt selbst festgelegt.
In PHP z.B. ist nicht entscheidbar, ob eine Variable einen String oder einen Integer hält. (Dies wird erst in einem Kontext ermittelt)
Keine Deklaration nötig
Variablen können mit del gelöscht werden
>>> a = 500 # a einen Wert zuweisen, >>> a # Dabei wird a angelegt 500 >>> del a # a löschen >>> a # Fehler: a nicht mehr vorhanden Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: name 'a' is not defined
3.2 Variablennamen
- Variablen und Funktionsnamen überlicherweise in lowercase_with_underscres
- Beginnen mit _ oder einem Buchstaben
- Enthält nur _, Buchstaben und Zahlen
- Variablen der form __irgendwas__ sind besondere Variablen. Diese bitte nicht selbst erfinden!
Soll eine Variable zufällig wie ein Schlüsselwort heissen, sollte man das so schreiben: class_, if_
Variablen, die nicht von anderen Entwicklern zugreifbar sein sollen schreibt man so: _privat, _interne_variable.
Achtung: Das ist nur eine Konvention. Es gibt keinen public/private-Mechanismus in Python!
3.3 Syntaxelemente
Unterscheidung zwischen Ausdrücken und Anweisungen:
| Ausdruck/Expression: | |
|---|---|
Liefert einen Wert zurück. (Vergleich, Funktionsaufruf, Addition, etc...) 5 + 10 "Ich bin ein Ausdruck" f(3.1415) a >= 7 not (a < 7 or a > 100) |
|
| Anweisung/Statement: | |
Entweder ein Ausdruck oder eine Zuweisung, Funktionsdefinition etc... print "Ich bin eine Anweisung" a = 8000 5 + 10 "Ich bin auch ein Ausdruck" |
|
3.4 Zeilenorientiertheit
Anweisungen enden mit der Zeile:
print ("Dies wird" " beides ausgegeben") "Dies nicht, es ist eine neue Anweisung"Ausnahme: Noch offene Klammern:
print ("Dies wird" " beides ausgegeben")oder Zeilenfortsetzung:
print "Dies wird\ beides ausgegeben"
3.5 Ausdrucksbeschränkung
Anweisungen und Ausdrücke dürfen nur weitere Ausdrücke enthalten, keine weiteren Answeisungen:
a = (print 6) # Fehler: print ist eine Anweisung a = (b = 7) # Fehler: b = 7 ist eine Anweisung a = 5 + 88 # Richtig if a = 5: # Fehler: a = 5 ist eine Anweisung! tue_irgendwas()
Code ist weniger dicht
Keine (versehentlichen) Zuweisungen in Bedingungen
3.6 Einrückung
Keine geschwungenen Klammern
Kennzeichnung der Blöcke durch Einrückung
Python
C
while a < 100: a = a * 2 b = b + 1 if b == 10: tue_etwas() b = 77while(a < 100) { a = a * 2; b = b + 1; if(b == 10) { tue_etwas(); b = 77; } }Laut Styleguide mit 4 Leerzeichen einrücken, niemals mit Tabs und schon gar nicht mit einer Mischung von Beidem!
4 Datenstrukturen
4.1 Tuple
- Aneinanderreihung von Werten, ähnlich Array
- Immutabel
- Verwendung zum Beispiel: x-y-z-Koordinaten
() # Leeres tuple
(5,) # Tuple mit einem Element
# (Das Komma ist wichtig, sonst Klammerausdruck!)
("a", "b") # Paar
(1, "x", 2.1) # Tripel4.2 Tuple-Zuweisungen
Automatischen Entpacken von Tuples bei Zuweisungen:
ein_tuple = (3.14, 42) pi, sinn_des_lebens = ein_tuple
Automatisches Packen und Entpacken bei Zuweisungen:
a, b = 3, 4 # Tausche x und y: x, y = y, x
4.3 Listen
- Ähnlich zu Tupeln, aber variabel in der Länge
- Mutabel
[] # Leere Liste [7] # Liste mit einem Element a = [1, 2, 3.1, "b"] a[1] = "XX" # a jetzt: [1, "XX", 3.1, "b"] del a[2] # a jetzt: [1, "XX", "b"]
Mit liste.append() lassen sich Elemente anhängen:
>>> meine_liste = ["Test", 123, "x"] >>> meine_liste.append(777) >>> meine_liste ['Test', 123, 'x', 777]
4.4 Sequenzen
Listen, Tuples und Strings sind Sequenzen
Sequenzen sind indizierbar:
>>> a = [1, "B", 3.33] >>> a[1] "B"
Nagative Indizes werden vom Ende gezählt:
>>> a = "Hallo!" >>> a[-1] "!" >>> a[-2] "o"
4.5 Slices
Mit der Slice-Syntax lassen sich Ausschnitte aus Sequenzen erzeugen:
>>> a = ("a", 1.1, -22, "DDD") >>> a[1:2] (1.1,)Merke: Die obere Grenze wird in der Regel nicht mitgezählt!
Ein Parameter kann weggelassen werden:
>>> a = "abcdefghijk" >>> a[2:] # Alles nach dem 2. Zeichen "cdefghijk" >>> a[:2] # Die ersten zwei Zeichen "ab" >>> a[-3:] # Die letzten 3 Zeichen "ijk"
4.6 Weitere Sequenzfunktionen
| Funktion | Beispiel |
|---|---|
| Länge der Sequenz | >>> len([1, 2, 3]) 3 |
| Konkatenation | >>> (2, 3) + (4, 5) (2, 3, 4, 5) >>> "Hallo " + "Welt" "Hallo Welt" |
| Vergleich | >>> (1, 5) < (1, 7) True >>> [1, 5] < [2, 1] True >>> "AAA" < "ABC" < "BBB" True |
4.7 Dictionaries
- Interne Bezeichnung: dict
- Hashtabellen, Schlüsseln werden Werte zugeordnet
- Mutabel
- Alle immutablen Werte können als Schlüssel verwendet werden
- Reihenfolge irrelevant!
>>> d = {
... "ein Schlüssel": 3.1415,
... 500: "Internal Server Error",
... (2, 3.2): "Zielposition",
... }
...
>>> d[500]
'Internal Server Error'
>>> d[600] # ==> Fehler
...
>>> d.get(600, "nicht gefunden")
'nicht gefunden'
5 Control-Flow
5.1 Funktionen
- Schlüsselwort def
- Default-Werte möglich
def meine_funktion(a, b, c=77): print a, b return c + 3
5.2 Funktionen aufrufen
Aufruf: Funktionsname mit Paramterliste:
>>> def add(a, b, c=5): ... return a + b + c ... >>> add(10, 4) 19 >>> add(10, 4, 1) 15
Man kann die Paramter beim Aufruf direkt benennen (keyword-Argumente):
>>> add(10, b=4) 19 >>> add(c=2, a=3.14, b=0) 5.14
5.3 Mehrere Parameter
Zusätzliche Parameter mit * abfangen:
>>> def viele_parameter(a, b, *args): ... print a, b, args ... >>> viele_parameter("Hallo", 55, "XY", 1, 44) Hallo 55 ('XY', 1, 44)Zusätzliche benannte Parameter mit ** abfangen:
>>> def viele_parameter(a, b, **kwargs): ... print a, b, kwargs ... >>> viele_parameter("Hallo", 55, c="XY", zahl=1, nummer=44) Hallo 55 {'c': 'XY', 'nummer': 44, 'zahl': 1}
5.4 Funktionen sind Objekte
- Funktionen verhalten sich genau wie alle anderen Werte
>>> def mittelwert(a, b): ... return (a + b)/2.0 ... >>> durchschnitt = mittelwert >>> mittelwert(10, 20) 15 >>> durschnitt(10, 20) 15
5.5 Bedingungen
- If-Anweisung funktioniert wie gewohnt
- kein select/case/switch o.Ä. vorhanden!
if 50 <= a < 60: print "a ist größergleich 50 und kleiner als 60" elif a > 100: print "a ist 100" else: print "sonst"
5.6 Schleifen
while: Wiederhole den Block solange die Bedingung erfüllt ist:
while a < 50: a = a * a print a
for: Iteriere über alle Elemente:
for wert in range(4, 50): print wert
Note
range(m, n) bzw. range(n) liefert eine Liste mit allen Zahlen von m (bzw. 0) bis einschließlich n - 1.
xrange(m, n) bzw. xrange(n) verhält sich ähnlich, liefert aber einen Iterator, belegt also nicht so viel Speicherplatz.
Siehe pydoc range, pydoc xrange
for x in ["a", "X", 77, "hallo"]: print x for zahl, wort in {3: "drei", 4: "vier", 5: "fünf"}.items(): print zahl, "schreibt man", wortNote
items ist eine Methode von dictonaries, die eine Liste mit Schlüssel/Wert - Paaren zurückgibt.
Diese Paare werden hier mit "zahl, wort" automatisch entpackt und zwei Variablen zugewiesen.
Siehe pydoc dict
5.7 Ausnahmen I
Wenn Fehler auftauchen, wird eine Exception ausgelöst
Exceptions sind Instanzen der Klasse Exception (oder davon abgeleiteten)
Execptions können mit try und except abgefangen werden:
try: a = 400 / 0 except ZeroDivisionError: print "Fehler: Kann nicht durch Null teilen!"
5.8 Ausnahmen II
- Verfahren: Möglichst wenig Code zwischen try und except haben. Möglichst genaue Fehler abfangen (nicht Exception oder StandardError)
- else-Zweig wird ausgeführt, wenn es keine Ausnahme gab
- finally-Zweig wird immer ausgeführt
datei = open("datei.txt", "r")
try:
datei.write('r bedeutet "Read-Only"!')
finally:
# Egal ob ein Fehler aufgetreten ist, oder nicht,
# schließe die Datei
datei.close()6 Operatoren
6.1 Division
Sind beide Operanden Integer, ist das Ergebis auch ein Integer (abgerundet):
>>> 3 / 2 1 >>> 3 / 2.0 1.5 >>> 3.0 / 2 1.5 >>> float(3) / 2 1.5
Lösung: Einen der Operanden zu float konvertieren
6.2 Modulo
Rest bei einer ganzzahligen Division: %:
>>> 21 % 5 1 >>> 10 % 3.3 0.10000000000000053
Funktioniert auch mit floats. Hier: 3.3 * n + 0.1 = 10 Achtung: float-Ungenauigkeit!
6.3 String-Formatting
Modulo-Operator bei Strings und Tupeln erzeugt einen neuen String, ähnlich sprintf unter C:
>>> "Um %d Uhr gibt es %s. Pi ist %f." % (12, "Mittagessen", 3.1415) 'Um 12 Uhr gibt es Mittagessen. Pi ist 3.141500.'
Es gibt viele weitere Formatierungsmöglichkeiten. Siehe http://www.python.org/doc/lib/typesseq-strings.html.
| %d | Integer-Wert in Dezimaldarstellung |
| %x | Integer-Wert in Haxadezimaldarstellung |
| %X | Integer-Wert in Hexadezimaldarstellung (Großbuchstaben) |
| %f | Float-Wert in Dezimaldarstellung |
| %s | String |
6.4 Vergleichsoperatoren
| Operator | Bedeutung |
|---|---|
| a == b | a und b haben den gleichen Wert |
| a is b | a und b sind das selbe Objekt |
| a < b, a > b | Größer / Kleiner |
| a <= b, a >= b | Größer-Gleich / Kleiner-Gleich |
| a in b | a ist in b enthalten (b z.B. Liste) |
>>> 5 in [7, "a", 5, 8.2] True >>> "hallo" in "Er hat nur hallo gesagt" True >>> "olla" in "Hallo" False
6.5 Logische Operatoren
| Operator | Bedeutung |
|---|---|
| a and b | a und b sind wahr |
| a or b | a oder b sind wahr |
| not a | a ist nicht wahr |
7 Übung: Kalenderprogramm 1
| Aufgabe: |
|
|---|---|
| Hilfen: |
|
7.1 Lösung
termine = {}
def neuer_termin(jahr, monat, tag, stunde, minute, text):
termine[(jahr, monat, tag, stunde, minute)] = text
def loesche_termin(jahr, monat, tag, stunde, minute):
del termine[(jahr, monat, tag, stunde, minute)]
def termine_am(jahr, monat, tag):
for (j, m, t, st, min), text in termine.items():
if (j, m, t) == (jahr, monat, tag):
print "%d.%d.%d: %s" % (t, m, j, text)8 Module
8.1 Importieren von Modulen
funktionen.py:
print "Dies ist Modul 1" def addiere(a, b): return a + b
main.py:
import funktionen print funktionen.addiere(5, 7)
Ausgabe:
Dies ist Modul 1 12
8.2 Das import-Statement
| Syntax | Importiert | Aufruf der importierten Funktion |
|---|---|---|
| import funktionen | Modul | funktionen.addiere |
| import funktionen.addiere | Objekt aus Modul | funktionen.addiere |
| from funktionen import addiere | Objekt direkt aus Modul | addiere |
| from funktionen import * | Alle Objekte direkt aus Modul Achtung: *-Importe sollten in der Regel nicht verwendet werden! |
addiere |
- Module werden beim Importieren immer komplett ausgeführt "Modul-Level-Code"
8.3 Main-hook
Soll code nur ausgeführt werden, wenn das Modul das Hauptprogramm ist, kann man folgenden "Trick" benutzen:
# ... if __name__ == '__main__': print "Hier ist das main-Modul"
8.4 Wichtige Module
| os: | Datei- und Prozessfunktionen |
|---|---|
| sys: | stdin, stdout, ... Python-Version, Betriebssystem >>> import sys
>>> print sys.version
2.3.5 (#2, Mar 6 2006, 10:12:24)
[GCC 4.0.3 20060304 (prerelease) (Debian 4.0.2-10)]
>>> sys.stdout.write("test\n")
test |
| datetime: | Datums- und Zeitfunktionen: >>> from datetime import datetime, timedelta
>>> heute = datetime.today()
>>> heute.strftime("%A, %d.%m")
'Thursday, 30.03'
>>> uebermorgen = heute + timedelta(2, 0)
>>> uebermorgen.strftime("%A, %d.%m")
'Saturday, 01.04' |
9 Übung: Kalenderprogramm 2
| Aufgabe: |
|
|---|---|
| Hilfen: |
|
9.1 Lösung
termine = {}
def neuer_termin(datum, text):
termine[datum] = text
def loesche_termin(datum):
del termine[datum]
def termine_am(datum):
for d, text in termine.items():
print "%s: %s" % (d.strftime("%A, %d.%m.%Y"), text)10 OOP
10.1 Klassen erstellen
class Fahrzeug(object):
farbe = "Rot"
geschwindigkeit = 0
def umlackieren(self, neue_farbe="blau"):
self.farbe = neue_farbeKonvention: Klassennamen in CamelCase
Klassen sind Namensräume, die Objekte enthalten (Funktionen oder z.B. Strings, etc...)
Klassen sind selbst mutable Objekte:
>>> Fahrzeug.farbe Rot >>> >>> Fahrzeug.farbe = "Silber" >>> Fahrzeug.farbe Silber
10.2 Vererbung
- Klassen können von anderen Klassen erben
- Konvention: Klassen erben von object
class Fahrzeug(object): farbe = "Rot" raeder = 4 class Auto(Fahrzeug): motoren = 1 class LKW(Auto): raeder = 8 class Fahrrad(Fahrzeug): raeder = 2 |
|
10.3 Instanzen erstellen
Instanzen sind Objekte, welche eine Klasse zur Vorlage haben:
>>> mein_auto = Auto() >>> mein_auto.farbe Rot
Instanzen sind mutabel
Funktionen in den Klassen werden als Methoden übernommen:
>>> mein_auto.umlackieren("Grün") >>> mein_auto.farbe Grün >>> Auto.umlackieren(mein_auto, "Grün")
10.4 Konstruktor
__init__ wird für jede neu erzeugte Instanz aufgerufen:
class Fahrzeug(object): def __init__(self, farbe, raeder=4): self.farbe = farbe self.raeder = raeder print "Das Fahrzeug wurde erstellt" mein_trike = Fahrzeug("Grün", 3)
10.5 Destruktor
__del__ Wird aufgerufen, wenn sie gelöscht wird:
class Fahrzeug(object): def __del__(self): print "Das Fahrzeug wird gelöscht" mein_fahrzeug = Fahrzeug() del mein_fahrzeug
Achtung
Die __del__-Methode wird nicht notwendigerweise sofort bei del mein_fahrzeug aufgerufen. Der Garbage-Collector entscheidet, wann das Objekt wirklich zerstört wird!
10.6 Konvertierungen überschreiben
Die Funktion __str__ konvertiert die Klasse zu einem String:
>>> class Fahrzeug(object): ... farbe = "Grün" ... raeder = 4 ... def __str__(self): ... return "Fahrzeug, Farbe: %s mit %d Rädern" % (self.farbe, self.raeder) ... >>> f = Fahrzeug() >>> str(f) 'Fahrzeug, Farbe: Grün mit 4 Rädern'
Ebenso z.B. __int__
10.7 Methoden und Vererbung
class Fahrzeug(object):
def fahren(self):
self.motor_anschalten()
self.gas_geben()
class Auto(Fahrzeug):
def fahren(self):
self.anschnallen()
self.handbremse_los()
self.motor_anschalten()
self.gas_geben()- Methoden können von erbenden Klassen überschrieben werden
- Es kann aber nützlich sein, die "Elternmethode" aufzurufen
10.8 super()
Mit super() kann man eine Elternmethode aufrufen:
class Auto(Fahrzeug): def fahren(self): self.anchnallen() self.handbremse_los() super(Auto, self).fahren()super() kümmert sich auch um einen vernünftigen Ablauf, wenn es mehrere Elternklassen gibt
Wenn man __init__ überschreibt, sollte man immer die Elternfunktion aufrufen!
10.9 properties
| Problem: | Eine Klasse soll Attribute haben, die eventuell von Funktionen abeglöst werden. |
|---|---|
| Lösung: | Properties verwenden. |
| Vorher | Nachher |
|---|---|
>>> class Uhrzeit(object): ... stunden = 0 ... minuten = 0 ... |
>>> class Uhrzeit(object): ... minuten = 0 ... def _setze_stunden(self, s): ... self.minuten += s * 60 ... ... def _hole_stunden(self): ... return self.minuten / 60 ... ... stunden = property( ... _hole_stunden, ... _setze_stunden) |
10.10 Spezielle Methoden
class Fahrzeug(object):
def herstellen(cls, farbe, anzahl):
# ...
herstellen = classmethod(herstellen)
Fahrzeug.herstellen("Silber", 100)
f = Fahrzeug()
f.herstellen("Silber", 100)- classmethod() erstellt aus einer normalen Methode eine Klassenmethode, die als ersten Parameter ihre Klasse erhält (und nicht mehr die Instanz!)
- Ähnlich dazu: staticmethod() erstellt eine Methode, die gar keine speziellen Parameter mehr erwartet
11 Übung: Kalenderprogramm 3
| Aufgabe: |
|
|---|
11.1 Lösung I
class Person(object):
def __init__(self, vorname, nachname):
self.vorname = vorname
self.nachname = nachname
class Student(Person):
_mnr = 1000000
def __init__(self, *args, **kwargs):
super(Student, self).__init__(*args, **kwargs)
self.matrikelnummer = Student.gen_mnr()
def gen_mnr(cls):
cls._mnr += 1
return cls._mnr12 Tricks und Kniffe
12.1 Code-Dokumentation
- Am Anfang von Modulen, Klassen unf Funktionen platzierte Strings nennt man Docstrings.
- Docstrings werden von den Dokumentations-tools ausgewertet.
dokumentiert.py:
""" dokumentiert.py Dieses Modul ist gut dokumentiert. """ def eine_funktion(a, b): """Auch kurze Docstrings sollten die 3-fachen "-Zeichen benutzen.""" return a * b / (a + b)
12.2 Iteratoren I
- Ein Iterator ist eine Funktion, welche Elemente zurückgibt.
>>> class TenSquares(object): ... def __init__(self): ... self.i = 0 ... def __iter__(self): ... return self ... def next(self): ... if self.i == 10: ... raise StopIteration ... self.i += 1 ... return self.i ** 2 ... |
>>> for x in TenSquares(): ... print x ... 1 4 9 16 25 36 49 64 81 100 |
12.3 Iteratoren II
Das file-objekt z.B. ist ein Iterator über die Zeilen einer Datei:
datei = open("datei.txt", "r")
for zeile in datei:
print ">", zeile12.4 Generatoren
- Einen Iterator selbst zu schreiben ist umständlich. Generatorfunktionen nehmen einem da viel Arbeit ab.
Folgender Generator tut genau dasselbe wie eben besprochene Iterator:
def TenSquares():
for i in range(1, 11):
yield i ** 2- yield ist ähnlich zu return, aber wenn die Funktion das nächste mal aufgerufen wird, wird sie an derselben Stelle wieder fortgesetzt.
yield kann z.B. benutzt werden, um Bäume zu durchlaufen, folgendes Programm gibt z.B. einen Baum in "inorder" aus:
class Baum(object):
def __init__(self, wert, links=None, rechts=None):
self.links = links
self.wert = wert
self.rechts = rechts
def inorder(self):
# linker Teilbaum
if self.links is not None:
for e in self.links.inorder():
yield e
# Eigener Wert
yield self.wert
# rechter Zeilbaum
if self.rechts is not None:
for e in self.rechts.inorder():
yield e
b = Baum(8, Baum(5, Baum(3), Baum(7)), Baum(12, Baum(10)))
for e in b.inorder():
print e12.5 Tricks mit Funktionen
Imperative Programmierer vergessen oft, dass Funktionen Objekte sind wie alle anderen auch:
def verdoppeln(zahl): return zahl * 2 def halbieren(zahl): return zahl / 2.0 def minus2(zahl): return zahl - 2 def anwenden(zahl, fname): funktionen = { "a": verdoppeln, "b": halbieren, "c": minus2, } meine_funktion = funktionen[fname] return meine_funktion(zahl)
12.6 Mengen
In Python 2.3:
>>> from sets import Set >>> s = Set([4, 5, 6, 1, 5, 5, 4]) >>> s Set([1, 4, 5, 6]) >>>
In Python 2.4:
>>> s = set([4, 5, 6, 1, 5, 5, 4]) >>> s set([1, 4, 5, 6]) >>>
12.7 List-Comprehensions
Um Listen zu erstellen kann man so genannte List-Comprehensions benutzen:
>>> ten_squares = [x ** 2 for x in range(1, 11)] >>> ten_squares [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
An Python 2.4 Kann man ähnlich einfach Generatoren erstellen:
>>> ten_squares = (x ** 2 for x in range(1, 11)) >>> ten_squares <generator object at 0xb7de816c> >>> ten_squares.next() 1 >>> for zahl in ten_squares: ... print zahl ... 4 9 16 25 (...)
Man beachte nochmals, das es einen wichtigen Unterschied zwischen Listen und Generatoren/Iteratoren gibt:
- Bei Listen liegen alle Werte im Arbeitsspeicher und müssen auch alle ausgerechnet worden sein, bevor man auf einen zugreifen kann. Daraus folgt auch, dass Listen nur endlich viele Werte beinhalten können!
- Generatoren bzw. Iteratoren hingegen sind Funktionen, die für jeden neuen Wert erneut aufgerufen wird. D.h. jeder Wert wird i.d.R. erst dann berechnet, wenn er gebraucht wird. Generatoren können so gebaut werden, dass sie zumindest theoretisch endlos viele Werte zurückgeben können. Dafür lassen sie sich aber nicht ohne weiteres indizieren!
12.8 Closures
Auch innerhalb von Funktionen können Funktionen definiert werden.
Diese haben nicht nur Zugriff auf ihre Parameter und auf globale Variablen, sondern auch auf lokale Variablen der umgebenden Funktion.
>>> def faktor(n): ... def nfach(zahl): ... return n * zahl ... return nfach ... >>> doppelt = faktor(2) >>> dreifach = faktor(3) >>> doppelt(4) 8 >>> dreifach(4) 12 >>>
12.9 Klassen sind Namespaces
Klassen lassen sich hervorragend als Container für Variablen mißbrauchen. Den selben Effekt kann man mit dicts erreichen, allerdings hat man bei Klassen meist weniger Schreibaufwand.
>>> class Farben(object): ... Rot = "#f02020" ... Gruen = "#20ff40" ... >>> Farben.Rot '#f02020'
>>> Farben = {
... "Rot": "#f02020",
... "Gruen": "#20ff40",
... }
>>> Farben["Rot"]
'#f02020'
An dieser Stelle sei erwähnt, das Python Klassenattribute intern auch immer als dict abspeichert. Man kann auf dieses dictionary zugreifen, in diesem Fall über Farben.__dict__
12.10 Diamantvererbung
- Es ist in Python durchaus erlaubt, Konstrukte wie die bekannte "Diamantvererbung" zu bauen
- Wenn man super() verwendet, entscheidet super, in welcher Reihenfolge die Vater-Funktionen aufgerufen werden, es wird sichergestellt, dass alle drankommen
12.11 Nützliche Funktionen
zip(liste1, liste2) erstellt aus einer Liste eine Liste von Paaren:
>>> zip([1, 2, 3], ["a", "b", "c"]) [(1, 'a'), (2, 'b'), (3, 'c')]
filter(funktion, liste) gibt eine Liste zurück die nur Werte aus Liste enthält für die funktion True liefert:
>>> filter(gerade, [1,2,3,4,5,6]) >>> [2, 4, 6]
map(funktion, liste) gib eine Liste der Ergebnisse von einer Funktion angewendet auf die Elemente von liste an:
>>> import math >>> map(math.sqrt, [25, 36, 81, 100]) [5.0, 6.0, 9.0, 10.0]
12.12 Persistente Objekte
Das pickle-Modul verwandelt Python-Objekte in Strings und erstellt Objekte aus solchen Strings. Auf diese Weise lassen sich Objekte einfach in Dateien speichern oder über das Netz übertragen!
>>> import pickle
>>> pickle.dump(a, open("mein_auto", "w"))
>>> del a
>>> a = pickle.load("mein_auto")
>>> a
<__main__.Auto object at 0xb7de94cc>
>>> a.farbe
'Gelb'
>>> a.typ
'Ente'
13 Anhang
Diese Präsentation ist online verfügbar unter: http://www.leetless.de/python-kurs.html
Auch als PDF: http://www.leetless.de/python-kurs.pdf
Diese Präsentation wurde in RestructuredText geschrieben.
13.1 Suchwörter für Python-Anwendungen
| 3D/Spiele: | soya, pyogre |
|---|---|
| Webprogrammierung: | |
| Django, WSGI | |
| GUI: | pygtk, pyqt, wxwidgets |
13.2 Literatur
| A byte of Python: | |
|---|---|
| http://abop-german.berlios.de | |
13.3 Andere nützliche Links
| Die offizielle Python Homepage: | |
|---|---|
| http://www.python.org | |
| Das deutsche Python Wiki: | |
| http://wiki.python.de | |
| Das deutsche Python Forum: | |
| http://python-forum.de | |
| Der Python Cheeseshop: | |
| http://cheeseshop.python.org/pypi | |
| Python Library Reference: | |
| http://www.python.org/doc/current/lib/lib.html | |