print 10 + 20 + 30 + \
40
print [1, 2,
3, 4]
print 1; a = 99; print a; a += 7; print a
for i in range(4): print i; print i+10
print
for i in range(4):
print i
print i + 10
# falsch:
# a = 5; for i in range(3): print i
and or notstatt
&& || !
try ... except ... else try ... finally raise pass
ab Python 2.5 zusätzlich:
try ... except ... finally
neue Anweisung ab Python 2.5:
with expression [as varname]
statements
Der Code-Block wird hier unter Steuerung eines Kontext-Managers ausgeführt, der sichert, dass am Anfang und/oder Ende des Blocks bestimmte Aktionen immer ausgeführt werden. So werden z.B. Files auch nach dem Auftreten einer Ausnahme generell geschlossen.
Anwendungsbeispiel:
# in Python 2.5 ist folgender Import noetig, weil "with" erst nach Python 2.5 zum # Standard-Sprachumfang gehoert from __future__ import with_statement with open('/etc/hosts') as f: for line in f: print line,
Detaillierte Erläuterung: CODE/with.py
import sys from math import pi, sinh from math import pi as PI from socket import *
Modul-Suchpfad:
>>> dir() ['__builtins__', '__doc__', '__name__'] >>> dir(__builtins__) ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', ... 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
Anmerkung:
Funktionen sind (wie alle Python-Objekte) first-class objects und können somit als Argumente und Rückkehrwerte von Funktionen auftreten
a = True b = 1 # Operatoren zum # Test auf wertmäßige Gleichheit: ==, != # Test auf Identität : is, is not print a == b # True print a != b # False print a is b # False print a is not b # True
def outer():
def inner():
print a
a = 9
inner()
# "del" ist hier ein Syntaxfehler, da die Variable a in der inneren Funktion
# referenziert wird
#
# SyntaxError: can not delete variable 'a' referenced in nested scope
del a
Diese Einschränkung wurde allerdings mit Python 3.2 aufgehoben, so dass
dort die del-Anweisung zulässig ist.
def outer():
def inner():
def innermost():
nonlocal a, b
print(a) # Ausgabe: 30
print(b) # Ausgabe: 20
a = 40 # aendert 'a' von inner()
b = 50 # aendert 'b' von outer()
a = 30
innermost()
print(a) # Ausgabe: 40
print(b) # Ausgabe: 50
a = 10
b = 20
inner()
print(a) # Ausgabe: 10
print(b) # Ausgabe: 50
outer()
x, y = 1, 2 x, y = y, x print x, y
a, b, c = 1, 5, 3 print a < b > c x = a == b == c print x a = b = c = 0 print a == b == c
| Ausdruck | Wert |
|---|---|
| x or y | wenn x falsch, dann y, sonst x |
| x and y | wenn x falsch, dann x, sonst y |
| not x | wenn x falsch, dann True, sonst False |
Beispiel: Umwandlung DOS- in Unix-Text-File:
python -c 'for line in open("/etc/hosts"): print line.rstrip("\r\n")'
oder
python -c 'for line in open("/etc/hosts", "U"): print line,'
Beispiel:
# -*- coding: utf8 -*- def my_generator(n = 5): """generiert die Folge der ersten n natürlichen Zahlen""" assert n > 0 i = 1 while i <= n: # yield statt return yield i i += 1 for j in my_generator(8): print j print for j in my_generator(): print j print for j in my_generator(0): print j
Beispiel:
s = 'abcdefg' print s[2:5] # ==> 'cde' print s[0] # ==> 'a' print s[-1] # ==> 'g' print s[:] # ==> 'abcdefg' # allgemein erstellt "[:]" eine Kopie des Originals; # bei CPython-Strings werden aber keine Kopien generiert l = list(s) print l # ==> ['a', 'b', 'c', 'd', 'e', 'f', 'g'] l[2:5] = 'x' # ==> Liste l wird manipuliert: ['a', 'b', 'x', 'f', 'g'] print ''.join(l) # ==> 'abxfg' l[:] = s[:2] # ==> Liste l wird manipuliert: ['a', 'b'] print l # ==> ['a', 'b'] print range(10)[::2] # ==> [0, 2, 4, 6, 8] print range(10)[::-1] # ==> [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] # Slicing hier konkret bei range() unnötig: print range(0,10,2) # ==> [0, 2, 4, 6, 8] print range(9,-1,-1) # ==> [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
# -*- coding: utf8 -*- # Liste der Zahlen 0 bis 9 for i in range(10): print i, print # Liste der Zahlen von 1 bis 14 mit Abstand 3: 1, 4, 7, 10, 13 for i in range(1, 15, 3): print i, print # mit xrange() statt range() for i in xrange(10000): if i > 10: # auf Grund des zeitigen Schleifenabbruchs ist xrange() effektiver, weil es # im Gegensatz zu range() nur die wirklich benötigten Zahlen der Folge und # keine Liste mit 10000 Elementen generiert break print i, print # xrange() akzeptiert dieselben Argumente wie range() for i in xrange(1, 15, 3): print i, print
ternärer Operator existiert vor Python 2.5 nicht
Operator-Syntax:
Alternativ-Notation, die auch vor Python 2.5 nutzbar ist:
# statt # a ? b : c # bei Python auch vor Version 2.5 nutzbare Alternative: # (a and [b] or [c])[0] # # Achtung: # a and b or c # funktioniert nicht, da generell c geliefert wird, wenn b falsch ist. Durch # den Trick mit der Liste klappt es, weil [b] auch dann wahr ist, wenn b selbst # falsch ist. import sys a = sys.argv[1] b = sys.argv[2] c = sys.argv[3] print (a and [b] or [c])[0] # statt der Listen könnte man auch Tupel verwenden print (a and (b,) or (c,))[0]
ab Python 2.5 nutzbare Notation:
# statt # a ? b : c # ab Python 2.5: # b if a else c import sys a = sys.argv[1] b = sys.argv[2] c = sys.argv[3] print b if a else c
Index:
#!/usr/bin/env python # -*- coding: utf8 -*- """ Hello World: als Modul oder Programm nutzbar """ # Definition der parameterlosen Funktion "hello" def hello(): """Funktion hello(): Ausgabe des Strings 'hello world'""" print 'hello world' if __name__ == '__main__': # die Funktion "hello" ausführen, da der vorliegende Code als Programm # gestartet und nicht als Modul importiert wurde hello()
Nutzung des Moduls helloworld.py:
#!/usr/bin/env python # -*- coding: utf8 -*- import helloworld # die Funktion "hello" des Moduls "helloworld" aufrufen helloworld.hello() # den DOC-String von "hello" ausgeben print helloworld.hello.__doc__ # Funktion help nutzen help(helloworld)
#!/usr/bin/env python # -*- coding: utf8 -*- # # Demonstration von Programmier-Paradigmen import sys # Python 2 oder 3? python2 = sys.version_info[0] == 2 if python2: # das range() von Python 3 heißt bei Python 2 xrange() range = xrange else: # ab Python 3 die Funktion filter() so redefinieren, dass sie immer eine # Liste liefert def filter(krit, seq): return list(__builtins__.filter(krit, seq)) # ======================================== # OOP - Objektorientierte Programmierung # ======================================== print('OOP') # Filterkriterium: True bei positiven Werten, sonst False def positiv(x): return x > 0 # Klasse für Sequenzen mit Filter-Funktion class filter_seq(object): def __init__(self, seq): self.seq = seq def filter(self, krit): # Nutzung der eingebauten Standard-Funktion filter(); # Rekursion unterbleibt, da die Objektmethode filter() # mit self.filter() angesprochen werden muss return filter(krit, self.seq) # Objekt der Klasse filter_seq instanziieren fs = filter_seq(range(-5, 5)) # für das Objekt die Methode filter aufrufen print(fs.filter(positiv)) print('------------') # ======================================== # imperative/prozedurale Programmierung # ======================================== print('imperativ/prozedural') # imperativ programmierte Filterfunktion def p_filter(krit, seq): result = [] for elem in seq: if krit(elem): result.append(elem) return result # Anwendung der Filterfunktion auf eine Liste print(p_filter(positiv, range(-5, 5))) print('------------') # ======================================== # funktionale (deklarative) Programmierung # ======================================== print('funktional') # Nutzung der eingebauten Funktion filter print(filter(positiv, range(-5, 5))) # dito, aber Nutzung einer anonymen Lambda-Funktion als Kriterium print(filter(lambda x: x > 0, range(-5, 5))) # List Comprehension: Listengenerierung durch funktionalen Ausdruck print([2 * x for x in range(-5, 5) if x > 0]) print('------------') # bei großen Listen empfehlen sich Generatorausdrücke statt List Comprehensions; # Generator-Objekt über einen Generatorausdruck erzeugen: gen = (2 * x for x in range(-100, 100) if x > 0) print(gen) # durch Iteration über dem Generator die Elemente ausgeben, die kleiner 21 sind for x in gen: if x > 20: break print(x) print('------------') # den Generator kann man auch ohne Generatorausdruck erstellen: def mygen(von, bis): x = von if von > 1 else 1 while x < bis: yield 2 * x x += 1 print('back in generator; new x =', x) # Nutzung des eigenen Generators for x in mygen(-100, 100): if x > 20: break print(x) print('------------') # ======================================== # AOP - Aspektorientierte Programmierung # ======================================== print('AOP') # ein Logger-Objekt als Wrapper zur Ergänzung des Aspekts (der # Querschnittsaufgabe) "Logging" class logger(object): def __init__(self, func): # Zähler für Anzahl der Funktionsaufrufe nullen self.calls = 0 # die Original-Funktion merken self.func = func def __call__(self, *args): # Aufruf-Zähler inkrementieren self.calls += 1 # Logging durchführen print('call %s to %s' % (self.calls, self.func.__name__)) # Aufruf der Original-Funktion self.func(*args) # die Funktion "myfunc" dekorieren und diese so mit dem Wrapper umgeben @logger def myfunc(*args): print(args) # indirekter Ruf der Funktion "myfunc" über den Logger als Wrapper; dessen # Funktion __call__ wird aufgerufen; sie fügt ihre Logging-Logik hinzu und ruft # dann die Original-Funktion "myfunc" myfunc(1, 3, 7, 9) myfunc(*(range(-5, 5))) myfunc('x', 'y', 'z') myfunc(True, False, None)
#!/usr/bin/env python # -*- coding: utf8 -*- """ Ausgabe der Argumente-Liste und der Umgebung """ import sys, os # sys.argv ist eine Liste print 'Argument-Liste: %s\n' % sys.argv # os.environ ist ein Dictionary # Keys --> Namen der Umgebungsvariablen # Werte --> Inhalte der Umgebungsvariablen # max. Länge der Keys ermitteln; wir übergeben dazu einen durch einen # Generator-Ausdruck erzeugten Generator an die eingebaute Funktion max() max_len = max(len(x) for x in os.environ) # formatierte Ausgabe des Dictionarys print 'Umgebung:' for key, value in os.environ.items(): # bei Python 2 existiert für die Iteration noch os.environ.iteritems(); bei # Python 3 wird nur noch os.environ.iter() unterstützt, das aber im Gegensatz # zu Python 2 keine Liste mehr liefert, sondern ein iterierbares View-Objekt print ' %-*s --> %s' % (max_len, key, value)
#!/usr/bin/env python # -*- coding: utf8 -*- """ Rechnen mit Python """ # Operator / soll "echte" Division ermöglichen; ab Python 3 ist dies der # Standard from __future__ import division import decimal # 2 Float-Zahlen von der Standard-Eingabe einlesen netto = float(input('Nettopreis: ')) mwst = float(input('Mehrwertsteuer in %: ')) # Anmerkung: raw_input() statt input() ist analog möglich und potenziell # sicherer, da es den gelesenen String nicht als Python-Ausdruck interpretiert, # sondern als reinen String liefert. # Ab Python 3 existiert nur noch input(), das sich dann aber wie raw_input() # verhält. # # netto = float(raw_input('Nettopreis: ')) brutto = netto * (1 + mwst / 100) print print 'Brutto:', brutto print 'Brutto mit 2 Stellen: %.2f' % brutto print 'Brutto gerundet auf 3 Stellen: ', round(brutto, 3) print print (1 + 011) * 0x0a, 1.35, 1.8E5, (3 + 1j) * 3, 3 ** 4 print 10 ** 20, 200L print print 'Division' print 1/3, 1 // 3 print a = 12.1 b = 2 c = a / b print c # 6.05 print str(c) # 6.05 print repr(c) # 6.0499999999999998 print `c` # nur bei Python 2: wie repr(c): 6.0499999999999998 # repr() wird im interaktiven Modus benutzt: # >>> 12.1 / 2 # 6.0499999999999998 # >>> a = decimal.Decimal(str(a)) b = decimal.Decimal(str(b)) c = a / b print repr(c) # Decimal("6.05") print c # 6.05 print # die Operationen mit Decimals kann man ziemlich fein über den Context steuern; # hier ein Beispiel: # den Default-Kontext auslesen default_context = decimal.getcontext() # einen neuen Kontext einstellen, der eine abweichende Präzision aufweist decimal.setcontext(decimal.Context(prec = 5)) # in einer Schleife jeweils zwei Zahlenpaare addieren for z1, z2 in ('1.11111111', '2.22222222'), ('3.33333333', '4.44444444'): a = decimal.Decimal(z1) b = decimal.Decimal(z2) print a print b print a + b # Achtung: der hier genutzte ternäre Operator existiert erst ab Python 2.5 print 'gerundet' if decimal.getcontext().flags[decimal.Rounded] else 'exakt' # den Default-Kontext wieder aktivieren decimal.setcontext(default_context) # Ausgabe: # 1.11111111 # 2.22222222 # 3.3333 # gerundet # 3.33333333 # 4.44444444 # 7.77777777 # exakt
#!/usr/bin/env python # -*- coding: utf8 -*- """ Demo zu Python-Strings und regulären Ausdrücken """ import sys, re, codecs, os io_encoding = 'PYTHONIOENCODING' in os.environ # Wir vermerken, ob die Umgebungsvariable PYTHONIOENCODING gesetzt ist. # # Das Manual von Python 3 sagt zu PYTHONIOENCODING: # If this is set before running the interpreter, it overrides the encoding # used for stdin/stdout/stderr, in the syntax encodingname:errorhandler. # The :errorhandler part is optional and has the same meaning as in # str.encode(). # # For stderr, the :errorhandler part is ignored; the handler will always be # 'backslashreplace'. # # Das Setzen von PYTHONIOENCODING ist z.B. dann wichtig, wenn die Ausgabe # eines Python-Programms in eine Pipe oder eine Datei umgelenkt wird. Ggf. # kommt es dabei zu einem Fehler, der nicht auftritt, wenn die Ausgabe auf # ein Terminal erfolgt: # # * Fehlerfreie Ausgabe auf ein UTF8-fähiges Terminal: # # python -c $'# -*- coding: utf8 -*-\nprint u"äöüß"' # # * Fehler bei Ausgabeumlenkung in eine Datei oder Pipe: # # python -c $'# -*- coding: utf8 -*-\nprint u"äöüß"' > out # Traceback (most recent call last): # File "<string>", line 2, in <module> # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128) # # python -c $'# -*- coding: utf8 -*-\nprint u"äöüß"' | wc -l # Traceback (most recent call last): # File "<string>", line 2, in <module> # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128) # 0 # # * Fehlerfreie Ausgabeumlenkung in eine Datei oder Pipe: # # PYTHONIOENCODING=utf8 python -c $'# -*- coding: utf8 -*-\nprint u"äöüß"' > out2 # PYTHONIOENCODING=utf8 python -c $'# -*- coding: utf8 -*-\nprint u"äöüß"' | wc -l # Apostroph und Doppel-Apostroph als gleichwertige String-Begrenzer s1 = 'abc"\n' "xyz" # Verkettung zweier String-Konstanten s2 = "a'b" raw1 = r'\d+' # entspricht: '\\d+' raw2 = r'\d+\\' # entspricht: '\\d+\\\\' # Achtung: einzelner Backslash darf bei Raw String nicht als letztes Zeichen # stehen: # r'\a\' ist also unzulässig print s1, s2, raw1, raw2 print ('Hallo' + ' Welt ') * 3 # Strings können mehrzeilig sein print ''' ich bin mehrzeilig ''' # Zeichenketten kann man zeichenweise durchlaufen (Sequenz) print for char in 'Python': print char # ord() --> ASCII- bzw. Unicode-Code eines Zeichens bzw. Unicode-Zeichens # ermitteln # chr() --> Zeichen mit angegebenem ASCII-Code generieren # unichr() --> Unicode-Zeichen mit angegebenem Code generieren print p = 'Python' + '%c%c.%c' % (chr(32), chr(0x32), chr(ord('5') + 1)) print p # Unicode-Zeichen ä if io_encoding: print unichr(228), ord(u'ä') s = 'Guido van Rossum'.upper() print '%s, %s' % (s[-10:], s[:5]) # Strings sind unveränderliche Objekte # # >>> a = 'aaa' # >>> a[1] = 'b' # Traceback (most recent call last): # File "<stdin>", line 1, in ? # TypeError: object does not support item assignment # Anwendung von String-Funktionen (Methoden von String-Objekten) s = s[:5] + ' ' + s[-6:] print s.replace(' ROSSUM', '') print s print for g in 'Guido van Rossum', 'Guido Westerwelle', 'Heinz': if g.endswith('Rossum') and g.startswith('Guido'): print g, '--> BDFL' elif 'Guido' in g: print g, '--> any other Guido' else: print g, '--> ???' s = 'Guido van Rossum' print print '/'.join(s.lower().split()) # Unicode-Strings unicode_str = u'äöü\N{Copyright Sign}' print 'latin1', unicode_str.encode('latin1') print >>sys.stderr, 'utf8', unicode_str.encode('utf8') if io_encoding: # die Original-Standardausgabe sichern orig_stdout = sys.stdout # den StreamWriter des UTF8-Codecs auf stdout anwenden: # >>> c=codecs.lookup('utf8') # >>> c # <codecs.CodecInfo object for encoding utf-8 at 0x98151ac> # >>> list(c) # [<built-in function utf_8_encode>, <function decode at 0xb7c22bec>, <class # 'encodings.utf_8.StreamReader'>, <class 'encodings.utf_8.StreamWriter'>] sys.stdout = codecs.lookup('utf8')[-1](orig_stdout) print 'utf8 via codecs', unicode_str # die Original-Standardausgabe wiederherstellen sys.stdout = orig_stdout print # kurzer Blick auf reguläre Ausdrücke # (?i) --> Flag i: ignore case # (?=egg) --> lookahead assertion muster = re.compile(r'(?i)spam\d+(?=egg)') s = 'x spaM1eGg spamlegg spam12xyc Spam88EGg spam23' print s # alle Vorkommen des Musters suchen print muster.findall(s) # erstes Vorkommen des Musters suchen res = muster.search(s) if res: print 'gefunden', s[res.start() : res.end()] print # match() sucht das Muster nur am String-Anfang s = '# anton=a22 berta=b11 caesar dora=' res = re.match(r'(\w+)=(\w+)', s) print 'match:', res # search() sucht das Muster irgendwo im String res = re.search(r'(\w+)=(\w+)', s) if res: print 'search:', res.groups() # Substitution print re.sub(r'(\w+)=(\w+)', r'\1:"\2"', s) # Substitution unter Nutzung einer eigenen Replace-Funktion, die für jedes # Match-Objekt gerufen wird; wir wandeln in Ausdrücken der Form "wort=wort" nur # das Wort links vom Gleicheitszeichen in Großbuchstaben um; group(0) und # group(1) sind hier identisch print re.sub(r'(\w+)(?==\w+)', lambda x : x.group(0).upper(), s) print re.sub(r'(\w+)(?==\w+)', lambda x : x.group(1).upper(), s)
# -*- coding: utf8 -*- """ Ausnahmebehandlung (Exception Handling) """ import sys def cat(filename): """Ausgabe einer Datei analog Kommando cat""" try: print open(filename).read(), except: print 'Kann %s nicht einlesen' % filename else: print 'Alles OK' cat('/etc/hosts') cat('/etc/hosts1') # ------------------------ # try / except / else print 'try / except / else' try: a = int(raw_input('Zahl: ')) if a == 0: sys.exit(0) if a < 7: raise ValueError except ValueError: print 'Ungueltiger Wert' except SystemExit: # diese Ausnahme ignorieren pass except: # sonstige Ausnahme erneut auswerfen raise else: # keine Ausnahme aufgetreten print 'Alles OK:', a # ------------------------ # try / finally print 'try / finally' for i in 1, 0: try: try: x = 1 / i finally: # finally wird immer ausgeführt und ist für Aufräumarbeiten gedacht; # eine aufgetretene Ausnahme wird nach finally erneut ausgeworfen print 'Division beendet' print x except: print 'Ausnahme %s, %s' % sys.exc_info()[:2] # ------------------------ # try / except / finally print 'try / except / finally' for i in 1, 0: try: x = 1 / i except Exception, e: print 'Ausnahme %s, %s' % (type(e), e) finally: # finally wird immer ausgeführt und ist für Aufräumarbeiten gedacht; # eine aufgetretene Ausnahme wird nach finally erneut ausgeworfen print 'Division beendet' print x
#!/usr/bin/env python # -*- coding: utf8 -*- """ Demo zu den Collection Types Tupel, Liste, Dictionary und Menge """ import sys python2 = sys.version_info[0] == 2 # Tupel print 'Tupel' # einelementiges Tupel mit Komma am Ende tupel1 = 1, print tupel1 # mehrelementiges Tupel tupel = 1, 2, 3 for i in 1, 2, 3: print i print # explizite Tupel-Klammerung generell möglich, aber bei Tupel-Zuweisungen und # Schleifen nicht nötig tupel1 = (1,) tupel = (1, 2, 3) for i in (1, 2, 3): print i print print tupel[0:2] a, b, c = tupel for i in tupel: print i print tupel + tupel, tupel * 2 print tupel + tuple('abcd') + tuple([1, 2, 3]) # hier ist eine explizite Klammerung nötig: print '%d %d %d' % (1, 2, 3) # Listen print '\nListen' liste = [1, 'abc', 2.3, 4l, (1, 2), {1: 2}, [5, 6, 7]] print liste for elem in liste: print type(elem), elem print # erstes Listenelement löschen del liste[0] for pos, elem in enumerate(liste): print pos, elem print # die ersten 10 Zeilen von /etc/passwd in umgekehrter Reihenfolge durchlaufen for line in reversed(open('/etc/passwd').readlines()[:10]): # die Felder in umgekehrter Reihenfolge zusammensetzen und ausgeben print ':'.join(reversed(line.rstrip('\r\n').split(':'))) print print 'Listen als Stacks und Queues' print liste print 'pop(3)' print liste.pop(3) print liste print 'append(25)' liste.append(25) print liste, len(liste) stack = [1, 2, 3] # queue durch Slicing als Kopie von Stack anlegen queue = stack[:] # für push und pop gebundene Methoden der Listen-Klasse verwenden push = stack.append pop = stack.pop print '\nStack' push(4); print stack push(5); print stack while stack: el = pop() print el, ',', stack print '\nQueue' enqueue = queue.append dequeue = lambda: queue.pop(0) enqueue(4); print queue enqueue(5); print queue while queue: el = dequeue() print el, ',', queue # Dictionaries print '\nDictionaries' d = {'Anton': 34, 'Berta': 19, 'Cäsar': 45, 'Alfred': 88, 'Bianca': 11} print '\nsortierte Schlüssel' print sorted(d.keys()) print sorted(d) print '\nsortierte Werte' print sorted(d.values()) print '\numgekehrt sortierte Werte' print sorted(d.values(), reverse = True) print list(reversed(sorted(d.values()))) print '\nPaare' for key, value in d.iteritems() if python2 else d.items(): print key, value print print d['Anton'] del d['Anton'] d['Alfred'] += 10 d.update(Marta = 23, Emma = 77) d = dict(d, Otto = 88, Adam = 43) d.update([('Jutta', 44), ('Jens', 17)]) print '\n', d for name in 'Anton', 'Emma', 'Jörg': print name, name in d # Mengen print '\nMengen' set1 = set('abcdax') set2 = frozenset((1, 2, 3, 1, 'b')) print 'set1:', set1 print 'set2:', set2 print 'Vereinigung:', set1 | set2, set1.union(set2) print 'Differenz:', set1 - set2, set1.difference(set2) print 'Schnittmenge:', set1 & set2, set1.intersection(set2) # hier noch die symmetrische Differenz, also die Differenz aus # Vereinigungsmenge und Schnittmenge bilden print 'Symmetrische Differenz:', set1 ^ set2, set1.symmetric_difference(set2) set1.add(45) set1.remove('x') print 'set1:', set1
#!/usr/bin/env python # -*- coding: utf8 -*- """ Demo zu den Steuerfluss-Anweisungen von Python """ import sys print 'Zeilen von stdin laut Länge klassifizieren' for line in sys.stdin: # \r und \n am String-Ende streichen line = line.rstrip('\r\n') # alle White-Spaces am Anfang und Ende des Strings streichen l = line.strip() if l == '' or l.startswith('#'): # Zeile ist leer oder Kommentar --> übergehen continue # Zeile nach der Länge klassifizieren l = len(line) if l < 10: print 'kurz', line elif l > 40: print 'lang', line else: print 'mittel', line print '---------------' print 'Integers eines Intervalls in zwei Integer-Faktoren zerlegen' # for mit else for n in range(2, 10): # Zahl n durchläuft das gewünschte Intervall for x in range(2, n): # x durchläuft alle möglichen ganzzahligen Faktoren if n % x == 0: # x teilt n ohne Rest und ist somit ein Faktor print n, 'gleich', x, '*', n/x break else: # reguläres Schleifenende erreicht --> kein Faktor ermittelt print n, 'ist eine Primzahl' # pass -- leere Anweisung if len(sys.argv) > 1: # muss noch implementiert werden pass
#!/usr/bin/env python # -*- coding: utf8 -*- """ Demo zu Python-Funktionen """ from math import pi def fib(n = 5): """ Folge der Fibonacci-Zahlen bis Zahl n ermitteln: a1 = 0 a2 = 1 an = an-2 + an-1 für n > 2 """ result = [] # zwei Variablen, die die jeweils letzten beiden Elemente der Fibonacci-Folge # enthalten; die Initialbelegung mit 1, 0 sichert, dass wir die Sonderfälle # a1 und a2 ganz regulär mit behandeln können an_minus_1, a_n = 1, 0 # in einer Schleife n Fibonacci-Zahlen generieren for i in range(n): # aktuelles a_n an die Resultat-Liste anhängen result.append(a_n) # aus den aktuellen letzten beiden Elementen wird die nachfolgende Zahl der # Folge berechnet; die beiden Variablen werden durch zyklische Verschiebung # aktualisiert an_minus_1, a_n = a_n, an_minus_1 + a_n return result print 'fib(10)', fib(10) print 'fib()', fib() print 'fib(0)', fib(0) print 'fib(1)', fib(1) print 'fib(2)', fib(2) def to_upper(liste): """alle Strings einer Liste in Großbuchstaben umwandeln""" for i in range(len(liste)): try: liste[i] = liste[i].upper() except: # offenbar kein String pass print l = ['anton', 1, 'berta'] to_upper(l) print l def make_unique(liste, keep = True): """alle mehrfach vorkommenden Listen-Elemente streichen""" if keep: # beim Streichen der Dubletten verändern wir die ursprüngliche Reihenfolge # der verbleibenden Elemente nicht result = [] for elem in liste: if elem not in result: result.append(elem) # die alte durch die neue Liste komplett ersetzen liste[:] = result else: # Element-Reihenfolge spielt keine Rolle: Liste in eine Menge umwandeln, # dadurch die Dubletten eliminieren; anschließend die Menge wieder in eine # Liste konvertieren; durch den Slicing-Ausdruck ":" manipulieren wir die # Liste, die der Funktion als Argument übergeben wurde; sie wird komplett # durch die neue Liste ohne Dubletten ersetzt liste[:] = list(frozenset(liste)) print l = [1, 8, 1, 2, 9, 2, 7, 2, 3, 7] m = l[:] make_unique(l) print l make_unique(m, False) print m def kreis(radius = None, durchmesser = None): """ Kreisumfang und -fläche berechnen Rückgabe: Tupel aus Umfang, Fläche, Fehlermeldung """ eps = 1e-10 if radius is durchmesser is None: return (None, None, 'Radius und Durchmesser nicht spezifiziert!') elif radius != None and durchmesser != None and abs(durchmesser - 2 * radius) > eps: return (None, None, 'Radius und Durchmesser passen nicht zusammen!') elif durchmesser is None: # Durchmesser aus Radius berechnen durchmesser = 2 * radius return (pi * durchmesser, pi / 4 * durchmesser ** 2, '') print print 'Kreisberechnnung: Umfang, Fläche, ggf. Fehlermeldung' for expr in ['kreis(radius = 3)', 'kreis(3)', 'kreis(durchmesser = 6)', 'kreis(3, 6)', 'kreis(3, 6.001)', 'kreis()']: print expr, '-->', eval(expr)
#!/usr/bin/env python # -*- coding: utf8 -*- """ Demo der Ein-/Ausgabe mit und ohne Formatierung """ import sys # Ausgabe nach stdout print 1, 2, 'hallo' # ohne Zeilenschaltung am Ende durch abschließendes Komma print 'Hallo', # mit Zeilenschaltung am Ende print 'Leute' # Ausgabe nach stderr print >>sys.stderr, 'Fehler' # zeilenweise von stdin lesen print 'zeilenweise von stdin lesen' for line in sys.stdin: print line, # ältere Variante: print 'nochmal zeilenweise von stdin lesen' while 1: line = sys.stdin.readline() if line == '': break print line, print '===' # File zum Lesen öffnen; # statt "open(...)" kann man bei Python 2.X auch "file(...)" schreiben f = open('/etc/hosts') # File geschlossen einlesen inhalt = f.read() f.seek(0) zeilen_liste = f.readlines() print inhalt print zeilen_liste print # File kopieren out = open('/tmp/hosts_dos', 'w') for line in open('/etc/hosts'): # im DOS-Format speichern print >>out, line.rstrip('\n') + '\r' # File schließen out.close() # noch eine Kopie im Unix-Format anlegen out = open('/tmp/hosts_unix', 'w') for line in open('/tmp/hosts_dos', 'U'): # durch den Universal Newline Mode (U) stellt Python die gelesenen Zeilen # automatisch im UNIX-Format bereit out.write(line) out.close() # Formatierung mit % for i in range(10): print '%10d, %10d' % (i, 2 * i) print # die Werte aus einem Dictionary nehmen d = { 'Anton': 10, 'Berta' : 20, 'Cäsar' : 30 } print '%(Anton)d, %(Berta)d, %(Cäsar)d' % d print # die Funktionen zfill() und rjust() nutzen for i in range(10): print str(i).zfill(10) print for i in range(10): print str(i).rjust(20)
#!/usr/bin/env python # -*- coding: utf8 -*- """ Aufruf externer Programme aus Python-Programmen """ import sys, os, tempfile, subprocess class MyError(Exception): """eigene Exception-Klasse""" def __init__(self, value = ''): Exception.__init__(self, value) def make_temp_file(): """sichere Erzeugung eines temporären Files""" if 'mkstemp' in dir(tempfile): # mkstemp() steht zur Verfügung (ab Python 2.3); dann nutzen wir es; # es liefert ein Tupel aus File Descriptor und File-Name; wir benötigen den # Namen; den Descriptor schließen wir fd, name = tempfile.mkstemp('', 'PYTMP.', '/tmp') os.close(fd) return name else: # mkstemp() steht nicht zur Verfügung; dann nutzen wir das # Unix-Standard-Tool mktemp über eine Pipe data = os.popen('mktemp /tmp/PYTMP.XXXXXXXX 2>/dev/null').readlines() if not data: # leerer Datei-Name --> Fehler raise MyError, 'Fehler beim Anlegen einer temporären Datei' # den Namen der temporären Datei zurückgeben return data[0].strip() def quote_shell_args(s): """ einen String so quotieren, dass man ihn literal als Wort an ein Bourne-Shell-Skript übergeben kann """ return "'" + s.replace("'", r"'\''") + "'" def run_external_command(*cmd_words): """externes Kommando über eine Bourne-Shell ausführen""" try: # Aufruf des Shell-Kommandos vorbereiten; # zuerst einen temporären Dateinamen für die Kommunikation mit dem # Shell-Skript generieren tfile = make_temp_file() # den Kommando-String generieren cmd = [] for word in cmd_words: cmd.append(quote_shell_args(str(word))) cmd.append('> %s 2>&1' % tfile) cmd = ' '.join(cmd) # Skript ausführen if os.system(cmd): # system() hat einen Fehler gemeldet; wir melden ihn über die Ausnahme # MyError raise MyError, 'Fehler beim Ausführen des externen Skripts ' + cmd # Ausgabe des Skripts zurücklesen und zurückgeben; das temporäre File wird # hier gleich mit gelöscht result = open(tfile).readlines() os.unlink(tfile) return result except MyError: # eine MyError-Ausnahme werfen wir unverändert wieder aus raise except: # alle anderen Ausnahmen werfen wir als MyError-Ausnahme aus raise MyError, 'Ausnahme: %s/%s' % (sys.exc_info()[0], sys.exc_info()[1]) # Start eines externen Kommandos via Shell os.system('date') print # externes Shell-Kommando starten und das Ergebnis über eine Pipe zurücklesen for line in os.popen('cal 6 2009 2>&1'): print line, # Implementierung mit dem neuen Modul subprocess statt os.system (ab Python # 2.4): for cmd in ('cal', '7', '2006'), ('rm', '/'), 'date1': try: status = subprocess.call(cmd) if status: print 'Fehler; Exit-Code:', status except: print 'Ausnahme: %s/%s' % (sys.exc_info()[0], sys.exc_info()[1]) print # Nutzung der eigenen Funktion run_external_command for cmd in ('cal', 7, 2006), ('cal1', 7, 2006): try: for line in run_external_command(*cmd): print line, print except MyError, obj: print obj.args[0], '\n' # bidirektionale Kommunikation mit einem externen Kommando subp = subprocess.Popen('touch /tmp/aaa ; rm -v /tmp/aaa / ; tr a-z A-Z', # line buffered bufsize = 1, # das Kommando an die Shell zur Ausführung übergeben shell = True, # über eine Pipe kommunizieren stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE ) s = 'aaa\nbbb\nccc' stdout, stderr = subp.communicate(s) print 'gesendet:', s print 'stdout:', stdout print 'stderr:', stderr
#!/usr/bin/env python # -*- coding: utf8 -*- """ Demo zu filter(), map(), reduce(), lambda List Comprehensions Generator-Ausdrücke """ import operator from math import pi, sin # filter(), map(), reduce() print 'Liste der nicht durch 2 und 3 teilbaren ganzen Zahlen zwischen 2 und 24' def f(x): return x % 2 != 0 and x % 3 != 0 print filter(f, range(2, 25)) print print 'Liste der dritten Potenzen der ganzen Zahlen von 1 bis 10' def cube(x): return x ** 3 print map(cube, range(1, 11)) print print 'Liste der Produkte der korrespondierenden Elemente der Intervalle [1, 7] und [7, 1]' seq = range(1, 8) def mul(x, y): return x * y print map(mul, seq, reversed(seq)) print print 'Summe der ganzen Zahlen von 1 bis 10' def add(x, y): return x + y print reduce(add, range(1, 11)) print print 'Summe einer Zahlenfolge' def mysum(seq): def add(x, y): return x + y # hier mit Start-Wert 0, so dass wir auch leere Sequenzen verarbeiten können return reduce(add, seq, 0) print mysum(range(1, 11)), mysum([]) print print 'bessere Implementierung durch Nutzung der eingebauten Funktion sum()' print sum(range(1, 11)), sum([]) print # Currying (partial function application): bestimmte Argumente an eine Funktion # binden # mit Closure: innere Funktion, die auf lokale Namen einer äußeren Funktion # Bezug nimmt print 'add3 mit Closure' def make_adder(n): def adder(x): #return operator.add(x, n) return x + n return adder add3 = make_adder(3) print add3(1) # mit lambda: anonyme Funktion print 'add3 mit lambda' #add3 = lambda x: operator.add(x, 3) add3 = lambda x: x + 3 print add3(1) # mit rufbarer Klassen-Instanz print 'add3 mit rufbarer Klassen-Instanz' class make_adder_class(object): def __init__(self, n): self.n = n def __call__(self, x): return x + self.n add3 = make_adder_class(3) print add3(1) # List Comprehensions print 'List Comprehensions' freshfruit = [' banana', ' loganberry ', 'passion fruit '] print [fruit.strip() for fruit in freshfruit] print vec = [2, 4, 6] print [3 * x for x in vec] print [3 * x for x in vec if x > 3] print [3 * x for x in vec if x < 2] print [(x, x ** 2) for x in vec] print vec1 = [2, 4, 6] vec2 = [4, 3, -9] print [x * y for x in vec1 for y in vec2] print [x + y for x in vec1 for y in vec2] print [vec1[i] * vec2[i] for i in range(len(vec1))] print # Pi auf eine steigende Zahl von Stellen runden print [str(round(pi, i)) for i in range(1, 10)] print # Generator-Ausdrücke print 'Generator-Ausdrücke' print print 'Summe der Quadratzahlen' print sum(i ** 2 for i in range(10)) print print 'Skalarprodukt zweier Vektoren' xvec = [10, 20, 30] yvec = [7, 5, 3] print sum(x * y for x, y in zip(xvec, yvec)) print print 'Tabelle der Sinus-Funktion' print dict((x, sin(x * pi / 180)) for x in range(0, 31)) print print 'Menge der Wörter eines Textes' print set(word for line in open('/etc/hosts') for word in line.split()) print print 'maximales Element einer Personen-Liste bestimmen' class Person(object): def __init__(self, alter, groesse): self.alter = alter self.groesse = groesse personen = [ Person(39, 172), Person(88, 165), Person(15, 181), Person(88, 175)] print max((person.alter, person.groesse) for person in personen) print print 'Zeichenfolge eines Strings umkehren und als Liste liefern' data = 'golf' print list(data[i] for i in range(len(data)-1, -1, -1)) # einfachere Implementierung ohne Generator-Ausdruck print list(reversed(data)) # oder mit Slicing print list(data[::-1])
#!/usr/bin/env python # -*- coding: utf8 -*- # Klasse mit Klassen- und Instanzvariablen sowie Name Mangling für __name class mytest(object): # 4 Klassenvariablen erzeugen a = 5 b = a + 5 __c = 9 * a __d__= __c + a # im Klassenkörper, aber außerhalb der Funktionen ist der Klassenname # unbekannt; die Anweisung # b = mytest.a + 5 # funktioniert daher nicht # Konstruktor / Initialisierer def __init__(self): # Instanzvariable x generieren self.x = 99 def myprint(self): # Zugriff auf die globalen Variablen a, b, _mytest__c, __d__ print a, b, __c, __d__ # Zugriff auf die Klassenvariablen über die Instanz (self) print self.a, self.b, self.__c, self.__d__ # dito über den Klassennamen, der innerhalb einer Funktion bekannt ist print mytest.a, mytest.b, mytest.__c, mytest.__d__ # Zugriff auf die Instanzvariablen x und y print self.x, self.y # 4 globale Variablen mit denselben Namen wie die Klassenvariablen anlegen a = 1 b = 2 _mytest__c = 3 __d__ = 4 # Instanz von mytest anlegen m = mytest() # Instanzvariable y anlegen m.y = 100 # Instanzvariable __z anlegen m.__z = 200 # Zugriff auf die Variablen; Python kennt nur öffentliche Attribute und daher # keine Sprachmittel zur Steuerung der Sichtbarkeit (z.B. public, private, # protected, ...) print m.a print m.b print m._mytest__c print m.__d__ print m.x print m.y print m.__z m.myprint() # die Klassenvariable a mit einem neuen Wert belegen; das geht nur über die # Klasse und nicht über die Instanz, also nicht über m.a mytest.a = 1000 print mytest.a # 2. Instanz erzeugen m2 = mytest() # darüber Zugriff auf die Klassenvariable a print m2.a
Modul BankKonto:
#!/usr/bin/env python # -*- coding: utf8 -*- """ OOP-Demo am Beispiel eines gebührenfreien und gebührenpflichtigen Bankkontos Idee: s. Tutorial "Programmieren lernen" von Alan Gauld """ from decimal import Decimal class SaldoError(Exception): """spezielle Ausnahme für Bankkonten-Operationen""" def __init__(self, saldo): Exception.__init__(self, 'Entschuldigung, Sie haben nur %6.2f EUR auf Ihrem Konto' % saldo) class BankKonto(object): """Realisierung eines gebührenfreien Bankkontos""" def __init__(self, initialBetrag = 0): """Konstruktor""" # Saldo wird im Attribut "__saldo" gespeichert; wegen der 2 Unterstriche # erfolgt ein "name mangling", also eine automatische Umbenennung zu # "_BankKonto__saldo" self.__saldo = Decimal(str(initialBetrag)) # anz_buchungen unterliegt keinem "name mangling" self.anz_buchungen = 0 print 'Konto erzeugt mit Saldo von %6.2f' % self.__saldo def buchung(self, betrag): """eine Buchung (Ein-/Auszahlung) vornehmen""" betrag = Decimal(str(betrag)) self.anz_buchungen += 1 if betrag >= 0: # nichtnegativer Betrag --> Einzahlung self.__saldo += betrag else: # negativer Betrag --> Auszahlung if self.__saldo >= abs(betrag): self.__saldo += betrag else: raise SaldoError, self.__saldo def __iadd__(self, betrag): """Überladung des Operators +=""" self.buchung(betrag) return self def __isub__(self, betrag): """Überladung des Operators -=""" return self.__iadd__(-betrag) def __str__(self): """Überladung von str()""" return '%6.2f' % self.__saldo def __repr__(self): """Überladung von repr()""" return self.__str__() def kontostand(self): """Abfrage Kontostand""" return self.__str__() def transfer(self, betrag, konto): """Transfer auf ein anderes Konto""" try: # Betrag vom Saldo des aktuellen Kontos subtrahieren self -= betrag # und dann zum Saldo des anderen Kontos addieren konto += betrag except SaldoError, obj: # wenn ein SaldoError ausgeworfen wurde, dann schlug die Subtraktion # fehl; sie wurde daher zusammen mit der nachfolgenden Addition nicht # ausgeführt print obj.args[0] class KostenKonto(BankKonto): """von BankKonto abgeleitete Klasse für ein gebührenpflichtiges Konto""" def __init__(self, initialBetrag = 0, gebuehr = 0.05): """Konstruktor; überschreibt die entsprechende Methode der Basisklasse""" # Konstruktor der Superklasse rufen super(KostenKonto, self).__init__(initialBetrag) # die Gebühr in der Property "gebuehr" unter Verwendung der entsprechenden # Set-Methode speichern self.gebuehr = Decimal(str(gebuehr)) def buchung(self, betrag): """erweiterte Buchungs-Methode; überschreibt die entsprechende Methode der Basisklasse""" print 'buchung in KostenKonto' # Direktzugriff auf die Gebühr unter Umgehung der Get-Methode der Property super(KostenKonto, self).buchung(betrag - self.__gebuehr) def get_geb(self): """Implementierung der Property-Methode __get__(): Ermittlung der eingestellten Gebühr""" print 'hole Gebühr' return self.__gebuehr def set_geb(self, geb): """Implementierung der Property-Methode __set__(): Setzen einer neuen Gebühr""" self.__gebuehr = Decimal(str(geb)) print 'neue Gebühr gesetzt:', geb def del_geb(self): """Implementierung der Property-Methode __delete__(): Löschen der Gebühr""" print 'Gebühr kann nicht gelöscht werden' # die Gebühr als Property definieren; # Zugriffe der Art obj.gebuehr nutzen dann die Property-Methoden, Zugriffe # der Art self.__gebuehr und obj._KostenKonto__gebuehr dagegen nicht gebuehr = property(get_geb, set_geb, del_geb, 'property gebuehr')
Nutzung des Moduls BankKonto:
#!/usr/bin/env python # -*- coding: utf8 -*- """ Demo zur Nutzung der Klassen des Moduls BankKonto """ from BankKonto import * print 'erzeuge b mit Initialbetrag 500 und k mit Initialbetrag 0 und Gebühr 0.03' b = BankKonto(500) k = KostenKonto(gebuehr = 0.03) # die Kontenobjekte mit dir() und vars() analysieren print print 'dir(b)' print dir(b) print print 'vars(b)' print vars(b) print vars(b) is b.__dict__ print print 'dir(k)' print dir(k) print print 'vars(k)' print vars(k) print vars(k) is k.__dict__ print print 'Kontostände' print 'b', b, b.kontostand() print 'k', k, k.kontostand() print for betrag in 100, 600: print 'Transfer %6.2f von b nach k' % betrag b.transfer(betrag, k) print 'b, k', b, k print for i in range(2): print '50 abheben von b und k' for varname in 'b', 'k': try: var = vars()[varname] var -= 50 print varname, var except SaldoError, obj: print 'Fehlschlag:', obj.args[0] print print '300 einzahlen auf k' k += 300 print k print print 'b._BankKonto__saldo', b._BankKonto__saldo print 'k._KostenKonto__gebuehr', k._KostenKonto__gebuehr print 'b.anz_buchungen', b.anz_buchungen print 'k.gebuehr', k.gebuehr k.gebuehr = 0.04 print 'k.gebuehr', k.gebuehr del k.gebuehr
Praktisches Beispiel vor der Theorie:
""" Nested Scopes Ausgabe: inner(): x in inner global x in module y in outer global set by inner() __main__ ------------------------- outer(): x in outer global x in module y in outer global set by inner() __main__ ------------------------- main(): global x in module global x in module y global set by inner() __main__ """ x = 'global x in module' y = 'y' z = 'z' def outer(): """aeussere Funktion""" x = 'x in outer' y = 'y in outer' def inner(): """innere Funktion""" global z x = 'x in inner' z = 'global set by inner()' print 'inner():' print x print globals()['x'] print y print z print __name__ print '-------------------------' inner() print 'outer():' print x print globals()['x'] print y print z print __name__ print '-------------------------' outer() print 'main():' print x print globals()['x'] print y print z print __name__
# -*- coding: utf8 -*- def myfunc(arg1, arg2, arg3 = '', arg4 = 55, *pos_args, **key_args): print arg1 print arg2 print arg3 print arg4 print pos_args print key_args print # Positions- und Schlüsselwort-Parameter lassen sich beim Funktionsaufruf durch # Tupel, Listen und Dictionaries ausdrücken: tupel = 1, 2 liste = [4, 5] dictionary = {'max' : 88, 'moritz' : 99} myfunc(1, arg4 = 66, *liste, **dictionary) # Resultat: # 1 # 4 # 5 # 66 # () # {'max': 88, 'moritz': 99} myfunc(3, arg4 = 68, *tupel, **dictionary) # Resultat # 3 # 1 # 2 # 68 # () # {'max': 88, 'moritz': 99} liste = [4, 5, 6] dictionary = {'arg4' : 111, 'max' : 88, 'moritz' : 99} myfunc(*liste, **dictionary) # Resultat: # 4 # 5 # 6 # 111 # () # {'max': 88, 'moritz': 99} liste = [4, 5, 6, 7, 8, 9] dictionary = {'max' : 88, 'moritz' : 99} myfunc(*liste, **dictionary) # Resultat: # 4 # 5 # 6 # 7 # (8, 9) # {'max': 88, 'moritz': 99} def tupel_print(a, (b, c), d): print a print b print c print d tupel_print(1, ('a', 2), 1.34) # Resultat: # 1 # a # 2 # 1.34
Beispiel:
#!/usr/bin/env python # -*- coding: utf8 -*- """ name mangling """ class C(object): # Konstruktor der Klasse C, der dem Attribut __x einen Wert zuweist; dieses # Attribut wird automatisch in _C__x umbenannt def __init__(self): self.__x = 99 # Objekt der Klasse C anlegen o = C() # Wert von __x ausgeben print o._C__x # OK try: print o.__x # Ausnahme: 'C' object has no attribute '__x' except AttributeError, obj: print obj o.__x = 88 # legt nun o.__x an print o.__x # OK
Beispiel:
#!/usr/bin/env python # -*- coding: utf8 -*- """ dynamische Polymorphie; späte Bindung """ class C(object): # Konstruktor, der die Attribute a und b füllt def __init__(self): self.a = 'a' self.b = 'b' # Methode zur Ausgabe von Attribut a def ma(self): print self.a # Methode zur Ausgabe von Attribut b def mb(self): print self.b # Objekt c der Klasse C anlegen c = C() # eine neue Methode mc des Objekts c erzeugen, die dessen Methode ma # entspricht c.mc = c.ma # über mc wird hier de facto ma gerufen; diese Entscheidung wird erst hier # dynamisch getroffen c.mc() # nun wird mb an mc zugewiesen c.mc = c.mb # über mc wird nun de facto mb gerufen c.mc()
Beispiel:
#!/usr/bin/env python # -*- coding: utf8 -*- """ gebundene und ungebundene Methoden """ liste = [1, 2, 3] # die Methode "append" gebunden und ungebunden bereitstellen gebunden = liste.append ungebunden = type(liste).append print gebunden # <built-in method append of list object at 0x...> print ungebunden # <method 'append' of 'list' objects> # Aufruf der gebundenen Methode gebunden(4) # eine 4 an die Liste anhängen print liste # [1, 2, 3, 4] # Aufruf der ungebundenen Methode ungebunden(liste, 5) # eine 5 an die Liste anhängen print liste # [1, 2, 3, 4, 5] # eigene Listen-Klasse vom eingebauten Typ "list" ableiten; hier sieht man die # "bound method" bzw. "unbound method" explizit class mylist(list): # Methode append() wird überschrieben def append(self, x): print 'appending', x # Methode append() der Basis- bzw. Superklasse wird gerufen super(mylist, self).append(x) # eine Instanz von "mylist" kreieren ml = mylist((1, 2, 3)) # die Methode 'append' wieder gebunden und ungebunden bereitstellen gebunden = ml.append ungebunden = mylist.append print gebunden # <bound method mylist.append of [1, 2, 3]> print ungebunden # <unbound method mylist.append> # Aufruf der gebundenen Methode gebunden(4) # appending 4 print ml # [1, 2, 3, 4] # Aufruf der ungebundenen Methode ungebunden(ml, 5) # appending 5 print ml # [1, 2, 3, 4, 5]
Beispiel für eine statische Funktion:
#! /usr/bin/python # -*- coding: utf8 -*- """ Button-Listen mit Tkinter (Python-Interface für das Toolkit Tk) """ from Tkinter import * class Button_Row(object): """Realisierung einer Button-Zeile in einem eigenen Fenster""" # 2 Klassen-Variablen: # - aktuelle Window-Nummer # - Tk-Instanz window_nr = 1 tk = None def button_print(self, (win_nr, bnr)): """Window-Nummer und Text von Button i der Button-Liste ausgeben""" print 'Window %s, %d, %s' % (repr(self), win_nr, self.button_list[bnr]['text']) # wir deklarieren "quit()" über den Decorator "@staticmethod" als statische # Methode, so dass sie kein implizites erstes Argument "self" hat und für # Instanzen sowie die Klasse gleichermaßen gerufen werden kann; Decorators # existieren seit Python 2.4 und beziehen sich auf die jeweils unmittelbar # folgende Funktionsdefinition @staticmethod def quit(): """Programm beenden""" print 'Bye' exit(0) def __init__(self, n): """Button-Liste aufbauen; n ist die Anzahl der Buttons""" if not Button_Row.tk: # falls noch keine Tk-Instanz existiert, ist eine zu erzeugen (also bei # Fenster 1) Button_Row.tk = self.window = Tk() else: # ab Fenster 2 erzeugen wir jeweils ein neues Toplevel-Fenster self.window = Toplevel() # einen Titel-String an den Window-Manager übergeben self.window.wm_title('Window %s' % self.window_nr) # die Button-Liste initialisieren self.button_list = [] if n < 1: # mindestens einen Button legen wir an n = 1 # schrittweise die einzelnen Buttons erzeugen for bnr in range(n): b = Button(self.window) if bnr < n-1: # normalen Text-Button erzeugen b['text'] = 3 * str(bnr) b['fg'] = 'red' # durch eine Lambda-Funktion mit einem die bnr enthaltenden # Default-Wert können wir die aktuelle bnr an die Funktion # button_print übergeben, da unsere Lambda-Funktion parameterlos # aufgerufen werden kann print '__init__, %s, %s, %s' % (repr(self), self.window_nr, bnr) b['command'] = lambda args = (self.window_nr, bnr): self.button_print(args) else: # Quit-Button erzeugen b['text'] = 'QUIT' b['fg'] = 'green' b['command'] = self.quit # den aktuellen Button packen b.pack({'side': 'left'}) # und an die Liste anhängen self.button_list.append(b) # Window-Nummer erhöhen Button_Row.window_nr += 1 # 3 Button-Leisten erzeugen und dann die Steuerung an die Mainloop von Tk # übergeben Button_Row(6) Button_Row(7) Button_Row(4) Button_Row.tk.mainloop()
für den Attribut-Zugriff werden spezielle Methoden gerufen:
| Methode | Erläuterung |
|---|---|
| __getattribute__(self, name) | Rückgabe des Attributs self.name, wobei die Standard-Implementierung dieser Methode das Attribut zunächst unter den Properties der Klasse und danach im Dictionary __dict__ der Instanz und anschließend rekursiv in den Dictionaries der Klasse sowie aller Basisklassen sucht (der erste Treffer wird verwendet) |
| __getattr__(self, name) | Rückgabe des Attributs self.name, falls es beim normalen Zugriff über __getattribute__() nicht gefunden wurde; Standard-Verhalten von __getattr__() ist der Auswurf der Ausnahme AttributeError |
| __setattr__(self, name, wert) | setzt für das Attribut self.name den Wert wert |
| __delattr__(self, name) | löscht das Attribut self.name |
Sofern es sich bei einem Attribut um ein Descriptor-Objekt handelt, werden dessen spezielle Methoden __get__(), __set__() und __delete__() gerufen.
Beispiel:
# -*- coding: utf8 -*- import sys # Verbose-Modus einschalten? verbose = len(sys.argv) > 1 and sys.argv[1] == 'v' # Definition einer eigenen Property-Klasse, die das Descriptor-Protokoll # implementiert, also mindestens eine der folgenden drei Methoden: # # __get__(self, instanz, klasse) # liefert den Attribut-Wert oder die Ausnahme AttributeError # # __set__(self, instanz, wert) # setzt einen Wert für das Attribut # # __delete__(self, instanz) # löscht das Attribut # class myproperty(object): def __init__(self, fget, fset, fdel): self.fget = fget self.fset = fset self.fdel = fdel def __get__(self, instanz, klasse): if verbose: print ' myproperty __get__ %s, %s, %s' % (repr(self), repr(instanz), repr(klasse)) return self.fget(instanz) def __set__(self, instanz, wert): if verbose: print ' myproperty __set__ %s, %s, %s' % (repr(self), repr(instanz), wert) return self.fset(instanz, wert) def __delete__(self, instanz): if verbose: print ' myproperty __delete__ %s, %s' % (repr(self), repr(instanz)) return self.fdel(instanz) # Eigene Property-Klassen sind meist entbehrlich, da man die durch die # eingebaute Funktion "property()" erzeugten Properties nutzen kann. # eine Klasse mit einem Property-Attribut, das ein Descriptor-Objekt der # Property-Klasse "myproperty" ist; die Definition solcher Property-Attribute # ist nur auf der Klassen-Ebene, nicht aber auf der Instanz-Ebene zulässig class C(object): def __init__(self): if verbose: print ' __init__ %s' % repr(self) self.a = 99 def __getattr__(self, name): if verbose: print ' __getattr__ %s, %s' % (repr(self), name) return '%s existiert nicht!!' % name if verbose: def __getattribute__(self, name): print ' __getattribute__ %s, %s' % (repr(self), name) return super(C, self).__getattribute__(name) def __setattr__(self, name, wert): print ' __setattr__ %s, %s, %s' % (repr(self), name, wert) return super(C, self).__setattr__(name, wert) def __delattr__(self, name): print ' __delattr__ %s, %s' % (repr(self), name) return super(C, self).__delattr__(name) # Funktionen, die vom Descriptor-Objekt gerufen werden; # sie verwalten den Wert der Property "p" im Instanz-Attribut "__p", das # wegen des Präfixes '__' als '_C__p' gespeichert wird def myget(self): if verbose: print ' myget %s' % repr(self) return '*** %s' % self.__p def myset(self, wert): if verbose: print ' myset %s, %s' % (repr(self), wert) self.__p = 2 * wert def mydel(self): if verbose: print ' mydel %s' % repr(self) del self.__p # Property-Attribut p als Descriptor-Objekt ausbilden p = myproperty(myget, myset, mydel) # Instanz "c" der Klasse "C" erzeugen c = C() print c.a # ruft c.__getattribute__('a') print c.b # ruft c.__getattribute__('b'); # da 'b' nicht existiert, folgt nun # c.__getattr__('b') c.a = 100 # ruft c.__setattr__('a', 100) c.b = 101 # ruft c.__setattr__('b', 101) print c.a # ruft c.__getattribute__('a') print c.b # ruft c.__getattribute__('b') del c.b # ruft c.__delattr__('b') # beim Attribut-Zugriff auf das Descriptor-Object werden die speziellen # Descriptor-Methoden verwendet c.p = 15 # ruft c.myset(15) print c.p # ruft c.myget() del c.p # ruft c.mydel() print c.p # ruft c.myget() # interne Umsetzung der zuvor gezeigten 4 Zugriffe: C.__dict__['p'].__set__(c, 15) print C.__dict__['p'].__get__(c, C) C.__dict__['p'].__delete__(c) print C.__dict__['p'].__get__(c, C)
Hier findet man viele Links und Online-Dokumentationen, u.a. Guidos Tutorial, eine (teilweise etwas schwer zu lesende) formale Sprachbeschreibung sowie eine umfangreiche Dokumentation der Module, die man als Programmierer immer zur Hand haben sollte. Diese Dokumente befinden sich meist lokal auf einem Rechner, auf dem die Python-Umgebung installiert ist.
eine sehr nützliche, umfangreiche Kurzreferenz für Programmierer
Python-Umgebung von ActiveState, deren Windows-Version nützliche Windows-Erweiterungen enthält und u.a. auch die IDE PythonWin anbietet
Python-Implementierung in Java
Python-Implementierung für .NET und Mono
Python-Implementierung in Python
umfangreiche Sammlung von Python-Software und Zusatz-Modulen
umfangreiche Sammlung von Informationen zu vielen Python-Modulen/-Paketen
Anmerkung: Bei einem Test am 4.6.2011 war diese Seite nicht erreichbar. Informationen zu Python finden sich aber hier: http://www.vclcomponents.com/Python/Web_Sites
eine interaktive Python-Shell mit einem deutlich erweiterten Funktionsumfang gegenüber der Standard-"Shell" von CPython: automatische Komplettierungen, dynamische Objekt-Introspektion, Suche in Namensräumen u.v.m.
eine standardmäßig mit CPython verteilte IDE
IDE, die verschiedene Sprachen unterstützt
IDE, die einen GUI Builder für wxWindows enthält
IDE für Python und Ruby
Hier finden sich neben der offz. Python-Dokumentation viele Verweise auf Einstiegs-Material und auch komplette Tutorien bzw. Bücher.
Es gibt je eine Version für Python 2 und 3.
mehr als 300 Tutorials, sortiert nach Kategorie und Titel
Eine passwort-geschützte PDF-Version der drei Auflagen kann heruntergeladen werden. Das Passwort findet man im Text des jeweiligen Buches ...
Informationssammlung von Steve Holden, dem Autor des Buches Python web programming