www.thomas-guettler.de/vortraege.html
iX 10/03, S.76: R.Fischbach, Weite Serpentinen (Neues in Python 2.2+2.3)
Python Online Dokumentation (locate '*python/html/index*')
www.python.org --> FAQs!
klassische Skriptsprache mit Skalaren und Zeichenketten
Listenverarbeitung
Objektorientierung
Syntaxprüfung beim Laden (Bytecode erzeugen)
keine Verwendung nicht belegter Variabler
keine illegalen Operationen:
"aha" + 15
ergibt Fehler!
Argumentprüfungen bei Funktionsaufruf u.ä.m.
Ausnahmebehandlung mit try ... catch (Bsp. Buchhaltung ...)
sehr viele Bibliotheken und Module rund um eine kleine Sprache
niedrige Einstiegsschwelle!
#!/usr/bin/python def a(n): # arctan(1/n) t = base/n; q = -n*n; x = t/q i = 3l while x != 0: t += x/i; x /= q i += 2 return t dig = 1000 # 1000 Stellen base = 10l**(dig+10) s = 48*a(18) + 32*a(57) - 20*a(239) print s
Rechenzeit: max. 50ms (Athlon XP 1700) ... schnell!
Download: www.sax.de/unix-stammtisch/..., lynx --> p (print)
Verschachtelung durch Einrückung
Funktionen
gängige Operatoren
Skalar: |
char, int, inf long; float=double, complex |
||
Sequenzen: |
|
|
|
|
Konstant: |
|
|
|
|
Strings: |
'abc', "abc", 'ein "Wort"', """über Zeilengrenze hinaus""" |
|
|
Unicodes: |
u'abc' |
|
|
Tupel: |
(1, 2, 'abc') (beliebige Typen aneinandergereiht, aber Konstante) |
|
veränderlich: |
|
|
|
|
Listen: |
a = [1, 2, 'abc']; a[2] = 3; print a [1, 2, 3] |
Mappings: |
|
|
|
|
Dictionaries: |
|
{ 'Bernd' : 80.2, 'Antonia' : 77.3, ...} (assoziatives Feld, Schlüssel muss konst. sein) |
Aufrufbare Typen: |
|
|
|
|
Funktionen, Klassen, Methoden (Funktion in Klasse) |
||
Klassen |
|
|
|
Files: |
|
|
fd = open('diddi', 'r'); rec = fd.readline(); ... |
Methoden und Attribute; Attribute sind wie Strukturelemente bei C, Bezeichnung »a.c«;
manche Attribute sind Funktionen und heißen dann Methoden ... (auch nur ein Datentyp)
Methoden gibt es bei Klassen und Modulen (die wie Klassen angesprochen werden).
Slices:
a = 'abcd' a[1:] 'bcd' a[1:2] 'bc' a[:-1] 'abc'
Methoden für Listen:
a = 'Eene|meene|muh' b = a.split('|') print b ['Eene', 'meene', 'muh'] from string import join print join(b,'*') Eene*meene*muh
map:
def f2(x): x *= 2 return x a = (1,2,3); b = map(f2, a); print b [2, 4, 6]
Weiter: reduce, filter;
Listenverarbeitung beschleunigt Python erheblich!
Praktisches Beispiel - Gewichtsmittelung in einer Leistungssport-WG
Aufgabe: Jeder wiegt sich täglich; am Ende sollen die Kurven von n-Tage-Mitteln ausgegeben werden (n ist personenspezifisch).
Als Programm mit Fallunterscheidungen und mehrdimensionalen Feldern, als Klasse einfach:
#!/usr/bin/python class Mean: def __init__(self, len): self.len = len # days for mean computing self.cv = [] self.cnt = 0 def mean(self, nr, date, mass): # nr = int, mass = float if not self.cv: self.s = self.len*[mass] self.sum = self.len*mass self.sum += mass - self.s[self.cnt] self.s[self.cnt] = mass self.cnt = (self.cnt+1)%self.len self.cv.append('%d %s %.2f' % (nr, date, self.sum/self.len)) # Instanzen erzeugen bernd = Mean(10) # Ruf von __init__(10) antonia = Mean(3) # Gewichte eingeben bernd.mean(1, '1.1.04', 82) antonia.mean(2, '1.1.04', 78.2) bernd.mean(1, '2.1.04', 83.4) antonia.mean(2, '2.1.04', 77.9) bernd.mean(1, '3.1.04', 84.8) antonia.mean(2, '3.1.04', 77.8) bernd.mean(1, '4.1.04', 83) antonia.mean(2, '4.1.04', 77.2) #Ausgaben erzeugen print "Bernd:" for s in bernd.cv: print s print "\nAntonia:" for s in antonia.cv: print s # Ausgabe: Bernd: 1 1.1.04 82.00 1 2.1.04 82.14 1 3.1.04 82.42 1 4.1.04 82.52 Antonia: 2 1.1.04 78.20 2 2.1.04 78.10 2 3.1.04 77.97 2 4.1.04 77.63
Beispiel aus dem realen Leben: virtueller Filepointer mit evtl. Umleitung und "less"
# return file object for redirection # (usually pipeline, evtl. with 'tee' and 'less') # arg: filename - default; if none then no request for redirection class redirect: def __init__(self, name=None): self.out = '' if name and io.yask('Ausgabe auf File umlenken', 'n'): while 1: file = io.dask('Ausgabe auf', name) if os.access(file, os.F_OK): if os.access(file, os.W_OK): if not io.yask(file + \ ' existiert bereits - überschreiben', 'n'): continue else: io.error(file + ' ist nicht beschreibbar') continue break self.out = 'tee ' + file + ' | ' self.out += 'less -F' def open(self): self.__fd = os.popen(self.out, 'w') def write(self, string): if self.__fd: try: self.__fd.write(string) except IOError: self.__fd.close() self.__fd = None def close(self): if self.__fd : try: self.__fd.close() except IOError: pass
Benutzung:
fd = redirect('Stamm.hmtl') # ... do something ... fd.open() # "less" zerhaut den Bildschirm!! fd.write('<it>meine erste Zeile<(it>'); # ... fd.close()
Bei Initialisierung mit a = b() werden Instanzen erzeugt, nur __init__() wird ausgeführt
Intern: Klasse ist wie Dictionary, Attribute und Methodennamen bilden Index.
"interne Übersetzung": Methodenaufruf
n1=hour_added(); n1.super(-1)
wird als
n1 = hour_added(); hour_added.super(n1, -1)
all members are public, all methods are virtual
lokaler Namensraum nicht default, Bezugname nur mit "self" ("this")
vor Klassenvar. muss immer 'self.' stehen (kann theor. auch anders heißen, so wie erstes Arg. der Funktion)
Initialisierung mit __init__(self, ...); Destruktor: __del__(self), wird aber nicht empfohlen
Name mangling für __-Namen: "private" (im Prinzip also ansprechbar, ginge genauso in C++ ...)
Beispiel:
class C: self.__eins = 1; a = C()
»a.__eins« kann als »a._C__eins« addressiert werden (sollte es aber nicht).
keine echte Klassen-Deklaration, sondern Anweisung:
import time
class min_sec:
ti = time.strftime('%M:%S')
def tr(self):
return time.strftime('%M:%S')
a1 = min_sec()
print a1.ti
12:17
print a1.tr()
12:21
# einige Zeit warten ...
a2 = min_sec()
print a2.ti
12:17
print a2.tr()
12:28
(Mehrfach)vererbung: Klassen werden ausgeführt! Beispiel als Fortsetzung von class min_sec:
class hour_added(min_sec): my_ti = time.strftime('%H:') + min_sec.ti n1 = hour_added() print n1.my_ti 18:12:17 #... warten ... n2 = hour_added() print n2.my_ti 18:12:17
--> altes min_sec.ti wird übernommen!
Klassendaten nachträglich erweiterbar:
a1.nachtraeglich = 'too late'
(neuerdings über __slot__ vermeidbar - legt Dictionary fest)
Klassendaten ohne 'self.' davor sind ähnlich wie statische Daten in C++: C.cnt += 1, können aber überschrieben werden!
Methodenrufe rel. langsam (warum?)
Datenattribute werden zuerst gesucht
Bei Vererbung wird Klassenobjekt "included", spätere Änderungen nicht mehr wirksam
Methoden können bei Vererbung überschrieben werden, Eltern können trotzdem explizit gerufen werden (ist eben Skript):
a = Parentclass.func(self, ...)
Mehrfachvererbung: Suche zuerst lokal, dann immer höher (von unten nach oben, links nach rechts); ändert sich noch
Gefahr: class B(A), class C(A), class D(B,C)
Overloading: Methoden __add__() etc. - sehr einfach
Namespaces wunder Punkt (verschachtelte Funktionen, vor allem aber Klassen)
Typeninkonsistenz u.U. erst zur Laufzeit bemerkt (aber Vor-Compilierung)
Typen vermerken (String/Zahl)!
Bei Listen aufpassen, es werden nur Referenzen übergeben:
a = [[1,2]]; b = 3*a; print b: [[1,2],[1,2],[1,2]] b[0][0] = 3; print b [[3,2],[3,2],[3,2]]
--> append! sogar a = b = [] ist gefährlich!
"Klassen sind kein Namensraum": lokale Funktionen müssen als »self.fctname(...)« gerufen werden!
auch bei Fkt. in Funktion kein Namensraum
for(...;...;...) geht nicht
finally + catch nicht zusammen
nachträgliche Erweiterbarkeit von Klassen gefährlich (konzeptionell)