PythonKurs

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 = 77
    while(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) # Tripel

4.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", wort

    Note

    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:
  • Ein Programm zur Terminverwaltung (Datum wird einem String zugeordnet)
  • Folgende Funktionen erstellen:
    • neuer_termin(jahr, monat, tag, stunde, minute, text)
    • loesche_termin(jahr, monat, tag, stunde, minute)
    • termine_am(jahr, monat, tag) -- gibt die Termine für diesen Tag auf dem Bildschirm aus
Hilfen:
  • Man darf annehmen, dass es zu einem Zeitpunkt nur einen Termin gibt ,-)
  • Eine globale Variable muss alle Termine enthalten
  • help("thema")

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:
  • Das bestehende Programm so umbauen, dass es das datetime-Modul nutzt.
  • Funktionen jetzt:
    • neuer_termin(datum, text)
    • loesche_termin(datum)
    • termine_am(datum)
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_farbe
  • Konvention: 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
vererbung1.png

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:
  • Klasse Person
    • Attribute: vorname, nachname
  • Klasse Student
    • Attribute: vorname, nachname, matrikelnummer
    • Klassenmethode: gen_mnr, die eine eindeutige Matrikelnummer generiert
  • Wenn ein Student erstellt wird, soll er automatisch eine Matrikelnummer erhalten

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._mnr

12   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 ">", zeile

12.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 e

12.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

PythonKurs (last edited 2009-06-17 16:14:14 by localhost)