====================
Einführung in Python
====================
Stefan Schwarzer <sschwarzer@sschwarzer.com>
Ubucon 2010
Leipzig, 2010-10-16
Überblick
---------
* zum Workshop
* erste Schritte im interaktiven Interpreter
* Namen
* Datentypen
* Bedingte Anweisungen (`if ... elif ... else`)
* Schleifen (`for`, `while`)
* Ausnahmen (`try ... except ... else`, `try ... finally`)
* Module
* eingebaute Funktionen
* Objektorientierte Programmierung (OOP)
Dieser Workshop
---------------
* Einführung in die Programmiersprache Python - ein Schnupperkurs
* keine Python-Kenntnisse erforderlich
* aber Programmierkenntnisse! (idealerweise auch in objektorientierter
Programmierung)
* Ziel des Workshops: Teilnehmer sollen hinterher in der Lage sein,
zumindest kleine Programme zu schreiben.
* Zeit ist *viel* zu knapp. :-/
Folgen:
- Erklärt werden nur die wichtigsten Konzepte und Bibliotheken.
- Eventuell ist nicht genug Zeit, um mit den einzelnen Übungen fertig
zu werden.
- Nicht jedes Detail muss verstanden werden.
- bitte Feedback zum Ablauf in der Pause (falls dringend, auch früher)
* verwendet wird Python 2.x (Python 3.1 ist aktuell, aber inkompatibel
zu Python 2.x; der meiste Code ist aber für Python 2.x geschrieben)
* zwischendurch Zeit für eigenen Experimente/Übungen;
bei Fragen fragen. ;-)
* Anmerkungen:
- Code innerhalb von Fließtext schließe ich normalerweise in
"umgekehrte" Hochkommas ("Backticks") ein. Ein Beispiel ist die
Zuweisung `beispiel = 1`.
- (G)Vim-Nutzer bekommen durch laden der Datei `talk.vim` Syntax-
Highlighting wie hier.
- Die Ausführung des meisten Beispiel-Codes in dieser Datei erledigt
ein cleveres ;-) Skript `example.py`, das auch Bestandteil der
Workshop-Dateien ist.
Wichtige Literatur / Links
--------------------------
* Python-Startseite: http://www.python.org/
* offizielle Python-Dokumentation
- Startseite: http://docs.python.org/
- Tutorial: http://docs.python.org/tutorial/
- Library Reference: http://docs.python.org/library/
- Language Reference: http://docs.python.org/reference/
* Python Style Guides
- http://www.python.org/dev/peps/pep-0008/
- http://www.python.org/dev/peps/pep-0257/
* Python Package Index: http://pypi.python.org/pypi
* Typische Python-Fehler:
http://sschwarzer.com/download/robustere_python_programme_clt2010_print.pdf
* Buch "Learning Python"
http://www.amazon.de/Learning-Python-Mark-Lutz/dp/0596158068/
behandelt Python 2.x *und* 3.x ! :-)
* Buch "Python: Das umfassende Handbuch"
http://www.amazon.de/x/dp/3836211106/
* deutschsprachige Portalseite zu Python: http://www.python.de/
Die Sprache Python
------------------
* ermöglicht kompakte, gut lesbare Programme
* ist relativ leicht zu lernen
* eignet sich für:
- System-Administration
- Web-Anwendungen
- wissenschaftliche Anwendungen
- das Verbinden verschiedener Systeme ("glue language")
- und vieles mehr
* unterstützt diese Programmier-Paradigmen:
- prozedural
- objektorientiert
- ein paar funktionale Elemente (aber keine "funktionale"
Programmiersprache wie beispielsweise Haskell)
* ist bei vielen Linux-Systemen (unter anderem Ubuntu) vorinstalliert
(oft Python 2.6).
Erste Schritte im interaktiven Interpreter
------------------------------------------
* Python-Interpreter lässt sich interaktiv benutzen
* sehr gut für Experimente (teilweise leider Probleme bei
Unicode-Strings, siehe unten)
* für den Einstieg in Python; Beispiel:
$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 1
1
>>> 2 * (3 + 4)
14
>>> print u"Hallo Welt!"
Hallo Welt!
>>> 1 + "2"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> def ausgabe(arg):
... print arg
...
>>> ausgabe(7)
7
>>> help("print")
The ``print`` statement
***********************
print_stmt ::= "print" ([expression ("," expression)* [","]]
| ">>" expression [("," expression)+ [","]])
``print`` evaluates each expression in turn and writes the resulting
object to standard output (see below). If an object is not a string,
it is first converted to a string using the rules for string
[viele weitere Zeilen]
>>>
* aber auch oft für Fortgeschrittene, um Python-Module (Bibliotheken)
auszuprobieren; Beispiel:
$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import urllib
>>> ufobj = urllib.urlopen("http://sschwarzer.com")
>>> data = ufobj.read()
>>> ufobj.close()
>>> data[:50]
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Stric'
* verlassen des Interpreters mit Strg-D direkt am Prompt (`>>>`)
* Tipp: erweiterten Interpreter IPython installieren:
$ sudo aptitude install ipython
Bezeichner ("Namen")
--------------------
* bestehen aus A-Z, a-z, 0-9 und _
* erstes Zeichen darf keine Ziffer sein
* Groß-/Kleinschreibung wird unterschieden; `hallo` und `Hallo`
sind unterschiedliche Bezeichner
* Schlüsselwörter *können* *nicht* als Namen verwendet werden
* Schlüsselwörter sind
and del from not while
as elif global or with
assert else if pass yield
break except import print
class exec in raise
continue finally is return
def for lambda try
* eingebaute Funktionen *sollten* *nicht* als Namen verwendet werden
siehe http://docs.python.org/library/functions.html
* PEP 8 sieht einige Konventionen für Namen vor. Einige der
Verwendungen werden später erklärt.
- Konstanten: `GROSSBUCHSTABEN_MIT_UNTERSTRICHEN`
- Klassen: `EineKlasse`
- Module: vorzugsweise `einmodul`, sonst `ein_model`
- alles andere: `mein_toller_bezeichner`
Gebrauch von Unterstrichen:
- nicht-öffentlicher Name: `_interner_name`
- "privates" Attribut in einer Klasse: `__total_intern`
- spezieller, von der Sprache genutzter Name: `__str__`
Datentypen
----------
* einfache Datentypen
- Zahlen (`int`, `long`, `float`, `complex`)
- Boolsche Werte = Wahrheitswerte (`bool`)
- Zeichenketten (`str`, `unicode`)
* zusammengesetzte Datentypen
- Listen (`list`)
- Tupel (`tuple`)
- Dictionarys = assoziative Arrays (`dict`)
- Sets (`set`)
* Funktionen, Klassen, Methoden
* Dateien
* Module
* und noch einige exotischere
Zahlen
------
* Beispiele:
print 2 + 3 * 7 # 23
print 8 / 4 # 2
# Ganzzahl-Division: ganzzahliger Teil bleibt, Rest wird verworfen
print 9 / 2 # 4
print 9. / 2 # 4.5
* Den Unterschied `int` vs. `long` kann man normalerweise
ignorieren; bei Bedarf werden `int`s in `long`s umgewandelt:
klein = 2 ** 5
print type(klein), klein
gross = 2 ** 1000
print type(gross), gross
* `float`-Werte entsprechen in etwa C's `double`-Typ und haben
eine Genauigkeit von ca. 16 Dezimalstellen.
print repr(1./7)
* `complex`-Werte bestehen aus Real- und Imaginärteil:
z = (0+1j) ** 2
print z, z.real, z.imag
* Bei Kombination von verschiedenen numerischen Datentypen werden
die Operanden in den "höchsten" Datentyp konvertiert
(`int` -> `long` -> `float` -> `complex`). Beispiele:
print 1 + 2.1
print 1 == 1.0
print 1 == (1+0j)
* Interpreter-"Spielzeit"
Boolsche Werte
--------------
* Boolsche Werte sind die Konstanten `True` und `False`.
wahr = (1 == 1)
print type(wahr), wahr
falsch = (1 == 0)
print type(falsch), falsch
* Prinzipiell sind `True` und `False` aber nur verkappte Integerwerte:
zwei = 1 + True
print type(zwei), zwei
null = False * 9
print type(null), null
Solche Ausdrücke können den Code schlecht lesbar machen; man sollte
sich gut überlegen, ob es auch übersichtlicher geht.
* Boolean-Werte lassen sich mit `or`, `and` und `not` verknüpfen
(Reihenfolge zunehmender Priorität).
a = 1
b = 2
print (a >= 1) and not (b < 2)
* `and` und `or` sind "short-circuit-Operatoren", das heißt, der
zweite Operand wird nicht ausgewertet, wenn das Ergebnis schon
feststeht. Das Ergebnis der Kombination ist dann der erste
Operand (aber nicht notwendigerweise `True` oder `False`).
* weiter unten mehr zu `bool`-Werten
Zeichenketten
-------------
* Python kennt keinen besonderen Typ für einzelne Zeichen
(wie `char` in C)
* Zeichenketten werden in Anführungszeichen eingeschlossen:
"Test"
'Er sagte, "Hallo!"'
"Wie geht's?"
"""Eine
"mehrzeilige"
Zeichenkette"""
'''Und
noch eine'''
* Diese so genannten "triple-quoted Strings" können alle anderen
Arten von Anführungszeichen enthalten außer "sich selbst". Folgendes
geht also *nicht*:
"""Triple-quoted Zeichenketten """der gleichen Art""" lassen
sich nicht schachteln."""
* Anführungszeichen können mit Backslashes maskiert werden:
print "Er sagte, \"Hallo!\""
* Alle oben genannten Zeichenketten sind vom Typ `str`. Es gibt auch
noch Unicode-Strings (siehe unten).
* Es gibt (ähnlich wie in anderen Sprachen) ein paar besondere
Zeichenketten:
\" maskiertes doppeltes Anführungszeichen
\' maskiertes einfaches Anführungszeichen
\n Zeilenumbruch (newline)
\t Tabulatorzeichen
\r Wagenrücklauf ("\r\n" ist ein unter Windows anzutreffendes
Zeilenwechselzeichen)
\b Backspace
und zur Definition von Zeichen durch Zeichencodes
\xhh Byte mit Hexadezimalcode hh
\uhhhh Unicode-Zeichen mit Code Point hhhh
\Uhhhhhhhh dito, mit 8 Hexadezimalziffern
siehe
http://docs.python.org/reference/lexical_analysis.html#string-literals
* Steht vor dem Anführungszeichen, das eine Zeichenkette einleitet,
ein `r`, ist die folgende Zeichenkette ein so genannter Raw-String.
In diesem Fall werden Maskierungen ignoriert. Beispiel:
print """abc\ndef"""
print
print r"""abc\ndef"""
* Strings können mit Vergleichsoperatoren `==`, `!=`, `<`, `>=`
usw. verglichen werden.
* Interpreter-Spielzeit
Mal so zwischendurch: Unicode
-----------------------------
* Die Zeiten von eindeutigem "plain text" sind lange vorbei.
* Unicode definiert etliche tausend Zeichen und ordnet jedem einen
Zahlencode (Code Point) zu. Dies ist nur ein abstrakter Wert und hat
zunächst nichts mit der Speicherung des Unicode-Textes zu tun.
* Zum physikalischen Speichern von Zeichen oder Übertragen über ein
Netzwerk müssen diese in ein so genanntes Encoding gebracht werden.
Unter Unix-Systemen am häufigsten sind UTF-8, ISO-8859-1 (Latin 1)
und ISO-8859-15 (Latin 9).
* Also: Unicode --- encode ---> Bytes
Bytes --- decode ---> Unicode
* Empfehlenswerte Links:
- http://www.p-nand-q.com/python/unicode_faq.html
- http://docs.python.org/howto/unicode.html
- http://www.joelonsoftware.com/articles/Unicode.html
Unicode-Strings
---------------
* Die bisher behandelten Zeichenketten (Strings) waren so genannte
Bytestrings (Typ `str`), also Byte-Folgen.
* Python kennt aber auch Unicode-Strings (Typ `unicode`).
* Um ein Unicode-Literal zu schreiben, muss man ein `u` vor
das Anführungszeichen schreiben:
byte_string = "Byte-String"
print type(byte_string), byte_string
unicode_string = u"Unicode-String"
print type(unicode_string), unicode_string
print
# Nimm an, dass der Byte-String in UTF-8 kodiert ist.
decoded_string = byte_string.decode("UTF-8")
print type(decoded_string), decoded_string
# Konvertiere den Unicode-String nach UTF-8
encoded_string = unicode_string.encode("UTF-8")
print type(encoded_string), encoded_string
* Kommen in einem Ausdruck Byte-Strings *und* Unicode-Strings vor,
wird im Zweifelsfall nach Unicode konvertiert.
s = "abc"
u = u"def"
print s < u
zusammen = s + u
print type(zusammen), zusammen
* Wenn man im Quelltext Unicode-Literale verwenden will, muss
man das Encoding in einem speziellen Kommentar innerhalb der
ersten zwei Zeilen der Datei angeben. Beispiel:
#! /usr/bin/env python
# encoding: UTF-8
...
Fehlt die Encoding-Zeile, wird ASCII angenommen. Dann können
effektiv keine "Sonderzeichen" in String-Literalen verwendet werden.
* *Anmerkung* Python 3 verwendet nur noch Unicode für Zeichenketten
und UTF-8 als Default-Encoding für Python-Quelltexte.
Nochmal Zeichenketten (Byte- und Unicode-Strings)
-------------------------------------------------
* Zugriff auf einzelne Zeichen:
uni = u"Dies ist eine Zeichenkette"
print uni[0] # Indizes starten bei 0
print uni[3]
print uni[-1] # negative Indizes zählen vom Ende
print uni[-3]
print uni[100] # Fehler
* Strings sind unveränderlich ("immutable"):
uni = u"Test"
uni[0] = u"F" # Fehler!
* Mit so genannten Slices kann man auf Bereiche zugreifen:
uni = u"Dies ist ein Test."
print uni[5:8] # erster Index, letzter Index plus 1
# Den Satz kann man auch so schreiben.
print uni[0:5] + uni[5:9] + uni[9:13] + uni[13:len(uni)]
print
# Fehlt ein Index wird der String-Anfang bzw. das Ende angenommen.
print uni[:3]
print uni[13:]
print uni[:] # eine Kopie des Strings
print uni[:-2] # alles ohne die letzten zwei Zeichen
* Slices lassen noch ein drittes "Argument" als Schrittweite zu
print u"umgedreht"[::-1]
* Spielzeit. Anregungen:
uni = u"abcdef"
print 1, uni[2:2]
print 2, uni[:100]
print 3, uni[4:2]
print 4, uni[:len(uni)]
print 5, uni[:-len(uni)+1]
print 6, uni[:-len(uni)]
print 7, uni[:-100]
Listen
------
* Listen nehmen null bis beliebig viele Objekte beliebigen Typs auf:
L = []
print "Leere Liste:", L
L = [1, "abc", u"def", [9]]
print "Liste mit Liste:", L
* Durch Indizes kann man auf einzelne Listen-Elemente zugreifen.
Da Listen veränderbar ("mutable") sind, kann man, anders als
bei Strings, auch Teile verändern.
L = [1, 2, "abc"]
print L[1] # Indizes zählen ab 0
L[2] = 7
print L # [1, 2, 7]
* Slices funktionieren wie bei Strings:
L = range(10) # die Liste [0, 1, 2, ..., 8, 9] (ohne 10!)
print L[:3] # [0, 1, 2]
L[2:6] = range(3) # linke und rechte Seite müssen nicht gleich lang sein
print L # [0, 1, 0, 1, 2, 6, 7, 8, 9]
print
print u"Noch mal in Zeitlupe ..."
L = range(10)
print u"Ursprüngliche Liste:", L
print u"Zu ersetzendes Stück:", L[2:6]
print u"Neues Stück:", range(3)
L[2:6] = range(3)
print u"Ergebnis:", L # von oben
* Hinzufügen von Elementen zu einer Liste am Ende geht mit den
`append`- und `extend`-Methoden:
L = [1, 2]
print u"Ursprüngliche Liste:", L
L.append(3)
print L
L.extend([4, 5])
print L
* Mit `insert` lassen sich auch Werte "in der Mitte" einfügen:
L = [1, 2, 3]
L.insert(1, 7)
print L
* Listen sind gleich, wenn sie die gleichen Werte in der gleichen
Reihenfolge enthalten.
L1 = [1, 2, 3]
L2 = [1, 2]
print L1 == L2
L2 = [1, 3, 2]
print L1 == L2
L2 = [1, 2, 3.0]
print L1 == L2
* Spielzeit. Was passiert hier?
L = range(8)
print L[:]
print L[:-2]
print L[3:3]
L[:] = [3, 2, 1]
print L
print
L = range(8)
L[3:2] = [-1, -2]
print L
Tupel
-----
* Tupel verhalten sich ganz ähnlich wie Listen, sind aber
unveränderlich.
t = (1, 2, 3)
print t[1]
print t[:2]
t[1] = 7 # Fehler
* leere Tupel und solche mit einem Element
leeres_tupel = ()
ein_element = (1,) # Komma zur Unterscheidung von geklammertem Ausdruck
* Oft explizit oder implizit verwendet wird das so genannte
"Tupel Unpacking" (das auch mit Listen auf der rechten Seite
funktioniert).
a, b = 1, 2
print a, b
a, b = b, a
print a, b
gruss = u"Hallo Welt!"
erstes_wort, zweites_wort = gruss.split()
print erstes_wort
print zweites_wort
Dictionarys
-----------
* Dictionarys enthalten Schlüssel-Wert-Paare.
d = {}
d = {2: "abc", 1: 2}
print d
print d[1]
print d[2]
print d[3]
Es gibt *keine* garantierte Reihenfolge der Paare!
* Jeder Schlüssel kann nur einmal vorkommen bzw. wird erneut dem
gleichen Schlüssel zugewiesen, wird der alte Wert ersetzt.
d = {2: "abc", 1: 2}
print d[1]
d[1] = "def"
print d
* Zuweisungen an einen neuen Schlüssel erzeugen einen neuen Eintrag.
d = {1: 2}
d["a"] = 17
print d
* Schlüssel müssen unveränderlich sein.
d = {}
d[(1, 2)] = 1
print d
d[[1, 2]] = 2
* Dictionarys sind gleich, wenn sie die gleichen Schlüssel-Wert-Paare
enthalten.
d1 = {1: 2, 3: 4}
d2 = {3: 4.0, 1.0: 2}
print d1 == d2
Sets
----
* Sets ähneln Dictionarys
s = set([1, 2, 3])
print s # das ist *keine* Liste
s.add(4)
print s
* Sets nehmen nur Werte auf, keine Paare
* es gibt *keine* garantierte Reihenfolge
* Werte müssen immutable sein
s = set()
s.add((1, 2))
print s
s.add([1, 2])
* Sets (Mengen) dienen (auch) zur Berechnung von Mengen-Operationen.
Beispiel: Welche Werte sind in Set 1, aber *nicht* in Set 2?
s1 = set(range(5)) # 0, 1, 2, 3, 4
s2 = set(range(3, 8)) # 3, 4, 5, 6, 7
print s1 - s2
print s1.difference(s2)
Welche Werte sind in Set 1 *und* Set 2?
s1 = set(range(5))
s2 = set(range(3, 8))
print s1 & s2
print s1.intersection(s2)
Namen und Zuweisungen
---------------------
* *Python kopiert nicht!* (außer auf ausdrückliche Anfrage)
* Eine Zuweisung verbindet einen Namen (links) und ein Objekt (rechts).
* Hilfreich: Der Operator `is` stellt fest, ob zwei Objekte
*identisch* und nicht nur wertmäßig gleich sind.
x = 1.0
y = x
print x is y
y = 1.0
print x is y # kann falsch sein (hängt von Python-Implementierung ab)
* Folgender Code ist legal (aber normalerweise *nicht* zu empfehlen):
a = 1 # int zuweisen
a = "abc" # str zuweisen
a = [1, 2] # list zuweisen
Hier wird jedesmal ein anderes Objekt mit dem Namen `a` verknüpft.
Das vorher verbundene Objekt wird "entsorgt", falls es sonst nicht
mehr benötigt wird.
Namen und Zuweisungen - Unveränderliche Objekte
-----------------------------------------------
* Zuweisungen
x = 1.0
y = x # x und y zeigen aufs gleiche Objekt
y = 1.0 # erzeuge ein neues Objekt 1.0 und lass y darauf zeigen
* nach der ersten Anweisung:
x ---> 1.0
* nach der zweiten Anweisung:
x ---+
+---> 1.0
y ---+
* nach der dritten Zuweisung
x ---> 1.0 (das zuerst erzeugte Objekt)
y ---> 1.0 (das in der dritten Zeile erzeugte Objekt)
Namen und Zuweisungen - Veränderliche Objekte
---------------------------------------------
* Was passiert hier?
L1 = [1, 2]
L2 = L1
L1.append(3)
print L1
print L2 # wurde auch verändert!
* Nach der ersten Anweisung ist `L1` ein Name für die Liste `[1, 2]`,
*die während der Zuweisung erzeugt wird* (bzw. unmittelbar vor der
eigentlichen Zuweisung).
L1 ---> [1, 2]
* Nach der zweiten Zuweisung ist die Liste unter zwei Namen bekannt.
L1 ---+
+---> [1, 2]
L2 ---+
* Der Aufruf der `append`-Methode verändert diese eine Liste.
* Diese "Anomalie" ist bei unveränderlichen Objekten nicht möglich.
* Spielzeit: Was passiert hier?
L1 = [1, 2]
L2 = L1
t1 = (L1,)
t2 = t1
L1.append(3)
print L1, L2
print L1 is L2
print t1, t2
print t1 is t2
String-Methoden
---------------
* Schon seit etwa acht Jahren haben Strings Methoden (gleich mehr
dazu). Die Verwendung des `string`-Moduls, um die gleichen Aufgaben
auszuführen, ist *veraltet*.
print "abc def ghi".split()
# VERALTET!
import string
print string.split("abc def ghi")
Das Modul selbst kann noch nützlich sein. Zum Beispiel enthält es
ein paar nützliche Konstanten:
import string
print string.digits
print string.ascii_letters # `string.letters` kann je nach Locale
# noch andere Zeichen enthalten
* einige nützliche String-Methoden
s = u"Dies ist ein String"
print s.count(u"i")
print s.encode("UTF-8") # vgl. decode
print s.startswith(u"Dies")
print s.endswith("ing")
print s.lower()
print s.upper()
teile = s.split()
print teile
print u"*".join(teile)
print u"abc\ndef\nghi".splitlines()
* noch mehr Nützliches
print u"abc" + u"def"
print 10 * "=-"
s = u"Dies ist ein String"
print len(s)
print u"ist" in s
String-Formatierung
-------------------
* Zeichenketten lassen sich sehr vielseitig miteinander und mit
anderen Objekten kombinieren.
* Syntax: `string_objekt % objekt`
* Beispiele:
print u"eins: %d" % 1
print u"%s %s" % (u"eins", u"zwei")
print u"%d plus %d ist %d" % (2, 3, 2+3)
print u"rechtsbündig mit zwei Nachkommastellen: %10.2f" % (1./3)
# Achtung! Anomalie bei Tupeln mit einem Element
print u"ein Integer: %s" % 3
print u"ein String: %s" % u"string"
print u"eine Liste: %s" % [1]
print u"ein Dictionary: %s" % {1: 2}
print u"ein Tupel: %s" % (u"1",)
* Variante: benannte Platzhalter und Dictionary
name = {"vorname": u"Stefan", "nachname": u"Schwarzer"}
print u"%(vorname)s %(nachname)s" % name
print u"%(nachname)s, %(vorname)s" % name
näheres unter
http://docs.python.org/library/stdtypes.html#string-formatting-operations
Listen-Methoden
---------------
* schon gesehen: `append(wert)` und `extend(iterable)`
* `iterable`: alles, über was iteriert werden kann; wird später
genauer erklärt. Bei `extend` ist `iterable` in der Praxis
meist eine Liste.
* `sort` sortiert eine Liste "in-place", das heißt, die Liste
selbst wird verändert. Zurückgegeben wird der spezielle Wert
`None`:
L = [3, -1, 9, 7]
print L.sort() # das ist wirklich `None`, aber `print`
# macht daraus implizit den String "None"
print L
`sort` akzeptiert ein optionales Argument `key`. Dabei
handelt es sich um eine Funktion, die auf alle Listenelemente
angewendet wird. Die Listenelemente selbst werden dabei nicht
verändert (aber natürlich ihre Reihenfolge).
L = ["def", "ABC", "Def", "abc"]
L.sort(key=str.lower)
print L
* `reverse` vertauscht die Reihenfolge der Liste "in-place"
und gibt `None` zurück.
* `index(wert)` gibt den Index des ersten Elements zurück, dessen
Wert gleich `wert` ist.
L = [1, 7, 3, 2]
print L.index(3)
print L.index(-1)
* ebenfalls nützlich:
L = [1, 2, 3]
del L[1]
print L
L = [1, 2, 3]
del L[1:]
print L
print
L = [1, 7, 3, 2]
print len(L)
L1 = [1, 2]
L2 = [2, 3]
print L1 + L2
L = [0]
print 10 * L
*Achtung* Bei der "Multiplikation" wird wie üblich *nicht* kopiert!
Das heißt, das/die betreffende/n Objekte werden mehrfach
referenziert:
innere_liste = [1, 2]
aeussere_liste = 5 * [innere_liste]
print aeussere_liste
innere_liste.append(3)
print aeussere_liste
* Spielzeit
Tupel-Methoden
--------------
Tupel haben einige Methoden, die auch Listen haben, aber keine,
die das Tupel verändern. (Tupel sind unveränderlich!)
Dictionary-Methoden
-------------------
* `keys` liefert eine Liste aller Dictionary-Schlüssel, `values`
liefert die Werte, und `items` eine Liste von
`(schluessel, wert)`-Paaren. Die Reihenfolgen aller drei
Methoden ist konsistent, *solange das Dictionary nicht
zwischendurch verändert wird*.
d = {"str": "abc", "int": 1, "liste": [1, 2, 3]}
print d
print d.keys()
print d.values()
print d.items()
print
d["tupel"] = (2, 3, 4)
print d
print d.keys()
print d.values()
print d.items()
* `get(schluessel, default)` gibt den Wert zu `schluessel` zurück
oder `default`, wenn der Schluessel nicht im Dictionary ist. Wird
`default` nicht angegeben, ist der Rückgabewert bei nicht
vorhandenem Schlüssel `None`.
d = {1: 2}
print d.get(1)
print d.get(2) # nicht im Dictionary
print d.get(2, 3)
print d
* `setdefault(schluessel, default)` funktioniert wie `get`, jedoch
wird außerdem bei *nicht vorhandenem* Schlüssel ein Schlüssel
`schluessel` mit Wert `default` ins Dictionary eingefügt.
d = {1: 2}
print d.setdefault(1)
print d.setdefault(2) # nicht im Dictionary
print d.setdefault(2, 3)
print d
* `update(dict2)` aktualisiert das Dictionary mit den Schlüssel-
Wert-Paaren aus dict2. Existieren Schlüssel in beiden Dictionarys,
"gewinnt" `dict2`.
d1 = {1: 2, 3: 4}
d2 = {3: 17, 5: 6}
d1.update(d2)
print d1
Das Dictionary `d1` wird dabei in-place verändert und `None`
zurückgegeben.
* ebenfalls nützlich:
d = {1: 2, 3: 4}
print (3 in d)
print (5 in d)
print len(d)
del d[1]
print d
Übung
-----
Welchen Wert hat das Dictionary `d` am Ende des folgenden Codes?
L = range(5)
L[:-1] = range(10, 12)
t = (1, 2, 3)
d = {1: L, 2: t}
L.append(u"Python ist toll".split()[0])
L = 2 * L
t.append(2)
Anweisungsblöcke
----------------
* Anweisungsblöcke werden *nicht* in `{ ... }` oder `begin ... end`
etc. eingeschlossen.
* Anweisungsblöcke entstehen durch gleichartige Einrückung; Beispiel:
for wert in liste:
if was_weiss_ich:
a = wert + 1
b = wert + 2
else:
a = wert + 3
b = wert + 4
eine_funktion(a, b)
* nach Python Style Guide (PEP 8) *vier* *Leerzeichen* pro
Einrückungsebene
* Der allergrößte Teil des existierenden öffentlichen Python-Codes
hält sich an die Konvention.
* Viele Programmiereditoren stellen sich beim Bearbeiten von
Python-Code automatisch passend ein. Zum Beispiel werden dann
durch Drücken der Tabulatortaste entsprechend viele Leerzeichen
eingefügt.
* sonst den Editor bitte entsprechend konfigurieren :-)
Bedingte Anweisungen
--------------------
* Die Struktur der `if`-Anweisung ist
if bedingung1:
block1
elif bedingung2:
block2
elif bedingung3:
block3
else:
block4
* Die `elif`- und `else`-Zweige sind optional (`elif` ohne
`else` ist auch möglich).
* Die Bedingungs-Ausdrücke müssen *nicht* eingeklammert werden.
* Nach den Bedingungen und dem `else` steht jeweils ein
Doppelpunkt.
* Die Bedingungs-Ausdrücke müssen *nicht unbedingt* einen
boolschen Wert liefern.
Wahrheitswerte
--------------
* Nicht nur `True` und `False` lassen sich als Ergebnisse eines
Bedingungs-Ausdrucks verwenden.
* Folgende Ausdrücke gelten in Python als falsch:
- `False`
- `None`
- alle Werte, die numerisch Null sind: 0 0.0 0+0j
- leere Strings: "" u""
- leere Container: [] () {} set() frozenset()
- der Vollständigkeit halber:
- Objekte benutzerdefinierter Klassen, die `__nonzero__`
definieren und dafür `False` zurückgegeben
- Objekte benutzerdefinierter Klassen, die `__len__`, aber
nicht `__nonzero__` definieren und `__len__` 0 liefert
* Alle anderen Werte sind wahr.
* leicht zu testen mit `bool(wert)`
print bool([])
print bool("")
print bool(set())
print bool(0)
print
print bool([1])
print bool(1e-50)
Fortsetzungszeilen
------------------
* "normalerweise" endet eine Python-Anweisung am Zeilenende
* Ausnahmen:
- am Ende der Zeile steht ein Backslash `\` (funktioniert *nicht*,
wenn der Backslash in einem Kommentar steht)
- wenn das Ende einer Zeile erreicht wird, sind noch Klammern offen
* Beispiele:
a = 1 # eine Zeile, eine Anweisung
b = 2 + \
3
c = 2 + # das funktioniert *nicht* \
3
d = (2 +
3)
e = [1,
2,
3, # (Komma nach dem letzten Element ist erlaubt)
]
Schleifen
---------
* `while`-Schleife:
while bedingung:
block1
else:
block2
Achtung: Doppelpunkte nach der Bedingung und `else`
Der `else`-Zweig ist optional und wird selten verwendet.
* überspringen einer Iteration mit `continue` (danach erneute
Evaluierung der Bedingung)
* abbrechen der Schleife mit `break`
* `continue` und `break` beziehen sich bei geschachtelten Schleifen
(einschließlich `for`-Schleife) auf die innerste Schleife, in der
sie stehen.
* `for`-Schleife:
for wert in iterable:
block1
else:
block2
Achtung: Doppelpunkte nach der Bedingung und `else`
Auch hier ist `else` optional und unüblich.
* `wert` kann auch ein Tupel sein -> Tupel-Unpacking
for erstes, zweites in [(1, "a"), (2, "b")]:
print erstes,
print zweites
print
* Bei Verwendung von `continue` wird die Schleife mit dem
nächsten Wert aus dem Iterable fortgesetzt.
* Durch die Verwendung der `for`-Schleifen-Syntax ist es selten
nötig, mit Indizes zu arbeiten. Falls man doch Indizes braucht,
zum Beispiel fürs Schreiben in Listen, gibt es die Funktion
`enumerate`:
L = range(5)
print L
for index, wert in enumerate(L):
L[index] = wert + 1
print L
* Es gibt auch noch Schleifen innerhalb eines Ausdrucks, so
genannte List Comprehensions. Als Beispiel berechnet der
folgende Code die Quadrate aller geraden Zahlen von 0 bis 10:
quadrate = [i**2 for i in xrange(10+1) if i % 2 == 0]
print quadrate
Prinzipiell kann man mehrere `for`- und `if`-Fragmente nutzen,
ich empfehle jedoch als Faustregel, maximal
- ein `for` und ein `if` oder
- zwei `for`
zu verwenden und sonst lieber explizite `for`- und `if`-Anweisungen.
Übung
-----
Schreiben Sie ein Skript zur Berechnung der Fakultät einer Zahl. Der
Ausgangswert soll auf der Kommandozeile übergeben werden.
Die Fakultät `n!` ist definiert als
n! = 1 * 2 * 3 * n
0! = 1
Für negative Zahlen ist die Fakultät nicht definiert. Für diesen
Fall bitte eine Fehlerbehandlung ausdenken. :-)
Tipp: Mit
import sys
n = int(sys.argv[1])
bekommt man das erste Kommandozeilen-Argument als Integer `n` ins
Skript.
Hier eine mögliche Lösung (mit `n` als Konstante, da ich bei meinem
Editor-Trick keine Kommandozeilen-Argumente übergeben kann):
n = 7
if n < 0:
print u"Argument %d ungültig!" % n
else:
fakultaet = 1
# `range(1, 1)` ist eine leere Liste - daher
# keine Sonderbehandlung für n == 0 nötig
for i in range(1, n+1):
fakultaet = fakultaet * i
print fakultaet
Mit kleinen Optimierungen:
n = 7
if n < 0:
print u"Argument %d ungültig!" % n
else:
fakultaet = 1
# `xrange` erzeugt keine Liste, sondern ein Iterable, das
# wenig Speicher benötigt
for i in xrange(1, n+1):
# so genanntes "augmented assignment"
fakultaet *= i
print fakultaet
Funktionen
----------
* allgemeine Syntax
def name(argumentliste):
block
* die wohl einfachste Funktion:
def leer():
# `pass` tut nichts (Behelfs-Block).
pass
print leer()
* mit einem Argument:
def addiere_eins(n):
return n + 1
print addiere_eins(2)
* mit zwei Argumenten, davon ein Default-Argument:
def addiere(n, summand=1):
return n + summand
print addiere(2)
print addiere(2, 4)
* Argumentliste kann beliebig viele Argumente enthalten
* Default-Argumente müssen am Ende stehen. Folgendes ist *ungültig*:
def addiere(summand=1, n):
return n + summand
print addiere(4, 2)
* Default-Argumente werden nur *einmal* - während der Definition -
ausgewertet!
def zwei_dazu(liste=[]):
liste.append(2)
return liste
print zwei_dazu([1, 2, 3])
print zwei_dazu()
print zwei_dazu()
print zwei_dazu()
* Mit der `return`-Anweisung kann man einen Wert zurückgeben. Das
kann auch ein Tupel sein (um effektiv mehrere Werte zurückzugeben).
* Eine Funktion darf mehrere `return`-Anweisungen enthalten. Diese
können auch Werte verschiedener Typen zurückgeben. Ob man das auch
tun will, *sollte man sich gut überlegen*.
* Fehlt die `return`-Anweisung oder wird sie von keinem Wert gefolgt,
ist der Rückgabewert `None`. Will man `None` zurückgeben, sollte
man das besser explizit mit `return None` tun.
* Wenn man im Aufruf Argument-Namen verwendet, kann man auch eine
andere Reihenfolge wählen, zum Beispiel
def komisches_append(liste, wert):
liste.append(wert)
return None
L = [1, 2, 3]
komisches_append(L, 4)
print L
L = [1, 2, 3]
komisches_append(wert=4, liste=L)
print L
* Gibt man direkt nach dem Funktionskopf einen String an, wird dieser
zum so genannten Docstring der Funktion.
def stupid_function():
"""Return `None`.
This function isn't really useful. It's only supposed to
show how a docstring is defined and used.
Docstrings (and program code in general) are usually
written in English.
"""
return None
print stupid_function.__doc__
* Mit der Syntax `*args` und `**kwargs` kann man beliebige Positions-
und Schlüsselwort-Argumente übergeben.
def zeige_argumente(*args, **kwargs):
"""Demonstriere Positions- und Schlüsselwort-Argumente."""
print u"Positions-Argumente:", args
print u"Schlüsselwort-Argumente:", kwargs
zeige_argumente(1, 2, "abc", a=7, x=(3, 4), b=[1, 2])
Übung
-----
Schreiben Sie eine Funktion zur Fakultätsberechnung. Die Funktion soll
als optionales Argument einen Fehlertext akzeptieren, der im Fall von
n < 0 verwendet wird.
def fakultaet(n, fehlertext=u"Argument %d ungültig!"):
"""Gib die Fakultät des Arguments n zurück.
Optional kann man als zweites Argument einen Fehlertext
angeben, der als Platzhalter für das ungültige Argument
%d, %r oder %s enthalten muss.
"""
if n < 0:
print fehlertext % n
# Später kommt auch eine "richtige" Fehlerbehandlung.
return None
fakultaet = 1
for i in xrange(1, n+1):
fakultaet *= i
return fakultaet
print fakultaet(0)
print fakultaet(1)
print fakultaet(7)
print fakultaet(-1)
print fakultaet(-1, fehlertext=u"Blöder Wert %s!")
Ausnahmen
---------
* um Programme zu schreiben, fehlt noch etwas: Ausnahmebehandlung
* Ohne Ausnahmebehandlung würde dieser Code zum Programmabbruch führen:
fobj = open("/nicht_da")
* Syntax für Ausnahmebehandlung:
try:
block1
except ausnahme_klasse1, ausnahme_objekt1:
block2
except ausnahme_klasse2, ausnahme_objekt2:
block3
else:
block4
* Der Teil `, ausnahme_objekt` kann auch fehlen, wenn er nicht
gebraucht wird (später mehr zu Ausnahme-Klassen und -Objekten).
* Es muss mindestens ein `except`-Block vorhanden sein, beliebig
viele können folgen.
* Der `else`-Zweig ist optional. Er wird ausgeführt, falls *keine*
der Fehlerbedingungen zutrifft.
* Beispiel:
try:
fobj = open("/nicht_da")
except IOError, exc:
# `exc` ist kein String, wird aber implizit umgewandelt
print u"Datei nicht gefunden: %s" % exc
else:
data = fobj.read()
fobj.close()
* Unbedingte Ausführung: Mit `try ... finally` wird ein Code-Block
auf jeden Fall ausgeführt, egal ob eine Ausnahme auftritt oder
nicht.
try:
block1
finally:
block2
* Beispiel:
try:
fobj = open("python_workshop.txt")
except IOError, exc:
print u"Datei nicht gefunden: %s" % exc
else:
# Nur dieser Teil ist neu!
try:
data = fobj.read()
finally:
# Wird auch ausgeführt, falls in `fobj.read` ein Fehler auftrat.
print "Closing ..."
fobj.close()
* Mit `raise` kann eine Ausnahme erneut ausgelöst werden:
try:
fobj = open("/nicht_da")
except IOError, exc:
# `exc` ist kein String, wird aber implizit umgewandelt
print u"Datei nicht gefunden: %s" % exc
raise
else:
data = fobj.read()
fobj.close()
* Man kann auch selbst Ausnahmen auslösen:
raise ValueError("ungültiger Wert!")
* Anmerkung: Oft benötigt man solch ein Konstrukt:
try:
...
try:
...
except ...:
...
except ...:
...
finally:
...
*Seit Python 2.5* kann man stattdessen schreiben:
try:
...
except ...:
...
except ...:
...
finally:
...
* Es gibt auch noch die Syntax
try:
...
except:
...
Hiermit werden (fast) alle Ausnahmen abgefangen. Allerdings auch
Ausnahmen, die man wahrscheinlich nicht fangen möchte. ;-)
try:
fobj = opne(eine_datei)
except:
print u"Datei nicht gefunden"
*Hier wird ein `NameError` verschleiert!*
Übung
-----
Schreiben Sie die Fakultätsfunktion so um, dass sie eine
Ausnahmebehandlung verwendet. Im Fall eines ungültigen Arguments soll
ein `ValueError` ausgelöst werden. (Ich gehe später auf einen besseren
Ansatz ein.)
def fakultaet(n, fehlertext=u"Argument %s ungültig!"):
"""Gib die Fakultät des Arguments n zurück.
Optional kann man als zweites Argument einen Fehlertext
angeben, der als Platzhalter für das ungültige Argument
%r oder %s enthalten muss.
"""
if n < 0:
kompletter_fehlertext = fehlertext % n
# Hack, weil `raise` nicht richtig mit Unicode umgehen kann :-/
if isinstance(kompletter_fehlertext, unicode):
kompletter_fehlertext = kompletter_fehlertext.encode("UTF-8")
raise ValueError(kompletter_fehlertext)
fakultaet = 1
for i in xrange(1, n+1):
fakultaet *= i
return fakultaet
print fakultaet(0)
print fakultaet(1)
print fakultaet(7)
try:
print fakultaet(-1)
except ValueError:
print u"Und weiter geht's ..."
print fakultaet(-1, fehlertext=u"Blöder Wert %s!")
Eigene Ausnahmeklassen
----------------------
* Normalerweise definiert man eigene Ausnahmeklassen, damit ein
Nutzer des Codes diese speziell handhaben kann.
* Hier erstmal als Rezept ... Eine eigene Ausnahme lässt sich mit
folgendem Konstrukt bauen:
# normalerweise `Error` am Ende des Namens
class UbuconLocationError(Exception):
pass
* Sie kann dann so verwendet werden:
def ubucon(uni):
...
# Hoffentlich nicht!
if uni_abgebrannt(uni):
raise UbuconLocationError("Tagungsort abgebrannt")
Der Aufrufer könnte folgendermaßen reagieren:
try:
ubucon("Uni Leipzig")
except UbuconLocationError:
ubucon("HTWK Leipzig")
Module
------
* Module sind Dateien, die Python-Code aufnehmen.
* Die Python-Distribution enthält über 400 Module, weitere sind
über den Python Package Index (PyPI, siehe oben) erhältlich.
* Eine Datei, die mit `.py` endet, kann sowohl Modul als auch
"direkt ausführbares Hauptprogramm" sein.
* Module werden mit der `import`-Anweisung geladen. Auf die Namen
innerhalb des geladenen Moduls kann dann mit der Notation
`modul.name` zugegriffen werden.
import example
# Auch Module können einen Docstring haben.
print example.__doc__
print example.EXAMPLE_FILENAME
* Natürlich lässt sich nicht nur auf Konstanten zugreifen, sondern
auf alle Namen, die im importierten Modul existieren.
* Es gibt auch noch Varianten des Imports:
from example import EXAMPLE_FILENAME
print EXAMPLE_FILENAME
Das spart zwar etwas Schreibarbeit, aber ist nicht zu empfehlen,
da mit der ersten Notation viel klarer wird, woher welche Namen
kommen.
* Auch die Kurzform `from example import *` ist normalerweise nur
für die Verwendung im interaktiven Interpreter gedacht.
* Ein Modul kann dem besonderen Namen `__all__` eine Liste der
Namen zuweisen, die mit der `*`-Form exportiert werden sollen.
__all__ = ['schlaue_funktion', 'PRAKTISCHE_KONSTANTE']
* Auch, wenn die Form `from modul import *` nicht empfehlenswert ist,
ist die Angabe von `__all__` dennoch nützlich, um anzudeuten, welche
Namen Bestandteil der Modul-Schnittstelle sind und welche nur intern
verwendet werden (sollen).
* Module können nur importiert werden, wenn sie
- im selben Verzeichnis liegen wie das Modul, das importiert
- im Modul-Suchpfad enthalten sind (`sys.path`, kann auch über
die Umgebungsvariable `PYTHONPATH` ergänzt werden)
$ export PYTHONPATH=/home/ich/python/meine_module
* *Achtung* *Nie* das gleiche Modul aus zwei oder mehr Verzeichnissen
innerhalb des Modulpfades importieren, auch nicht implizit!
Beispiel: Das aktuelle Verzeichnis ist `meine_module`, gleichzeitig
ist `PYTHONPATH=/home/ich` gesetzt und `meine_module` ist ein
Unterverzeichnis davon. Die `import`-Anweisungen
import modul2
from meine_module import modul2
führen dann aus Sicht von Python zu *zwei unterschiedlichen*
Einträgen in `sys.modules` und damit zwei Modul-Identitäten und
damit einer Art Schizophrenie.
* Viele Python-Programme haben als letzte Zeilen etwas wie
if __name__ == '__main__':
tu_was()
Die Anweisungen in der `if`-Anweisung werden nur ausgeführt, wenn
die Datei als "Hauptprogramm" ausgeführt wird, aber nicht beim
Import als Modul. (Hintergrund: `__name__` enthält den Namen des
Moduls, in dem die `if`-Anweisung steht; im Fall des
"Hauptprogramms" ist dieser Name `__main__`.)
* Anmerkung: Als Erweiterung des Modul-Gedankens können Module
wiederum in "Packages" gesammelt werden. Normalerweise wird ein
Package definiert, indem in einem Verzeichnis eine Datei
`__init__.py` abgelegt wird.
paketverzeichnis
__init__.py
modul1.py
modul2.py
Module aus dem Package können dann so importiert werden:
import paketverzeichnis # importiert implizit __init__.py
import paketverzeichnis.modul1
# üblichste Form
from paketverzeichnis import modul2
from paketverzeichnis import modul2 as anderername
# eher nicht empfehlenswert (siehe oben)
from paketverzeichnis.modul2 import name1, name2
* Die Import-Anweisung kann auch mit einer "Umbenennung" verknüpft
werden, um Namenskollisionen zu vermeiden:
from paket1 import modul as paket1_modul
from paket2 import modul as paket2_modul
Übung
-----
Verlegen Sie die Fakultäts-Funktion in ein Modul. Schreiben Sie eine
weitere Python-Datei, die die Funktion aus dem Modul verwendet.
# encoding: UTF-8
# fakultaet.py
__all__ = ['fakultaet']
def fakultaet(n, fehlertext=u"Argument %s ungültig!"):
"""Gib die Fakultät des Arguments n zurück.
Optional kann man als zweites Argument einen Fehlertext
angeben, der als Platzhalter für das ungültige Argument
%r oder %s enthalten muss.
"""
if n < 0:
kompletter_fehlertext = fehlertext % n
if isinstance(kompletter_fehlertext, unicode):
kompletter_fehlertext = kompletter_fehlertext.encode("UTF-8")
raise ValueError(kompletter_fehlertext)
fakultaet = 1
for i in xrange(1, n+1):
fakultaet *= i
return fakultaet
# encoding: UTF-8
# fakultaet_rechner.py
import fakultaet
argumente = [0, 1, 2, 5, 10]
erwartete_ergebnisse = [1, 1, 2, 120, 3628800]
for argument, erwartet in zip(argumente, erwartete_ergebnisse):
ergebnis = fakultaet.fakultaet(argument)
if ergebnis != erwartet:
print u"Fehler! %s != %s" % (ergebnis, erwartet)
try:
ergebnis = fakultaet.fakultaet(-1)
except ValueError:
pass
else:
print "Fehler! fakultaet hätte ValueError auslösen sollen."
Wichtige Module
---------------
* Eine Python-Installation stellt einige hundert Module zur Verfügung.
Eine Liste der Module ist unter http://docs.python.org/modindex.html
Die Module `sys` und `os` kommen in praktisch jedem Python-Programm
vor. Die darauf folgenden Module sind alphabetisch sortiert.
* `sys`: System-Informationen, zum Beispiel `sys.path`, `sys.modules`,
`sys.argv`
* `os`: verschiedene Datei- und Prozess-Operationen, zum Beispiel
liefert `os.listdir` eine Liste der Verzeichnisse und Dateien im
aktuellen Verzeichnis
`os.path`: Dateioperationen, zum Beispiel
`os.path.join("dir1", "dir2", "datei")` -> `"dir1/dir2/datei"`
mit den passenden Trenn-Symbolen. `os.path` wird durch `import os`
automatisch geladen.
* `cgi`: einfache Tools für CGI-Skripte. Es gibt viele Web-Frameworks
für Python, dennoch ist `cgi` noch nützlich. Zum Beispiel maskiert
`cgi.escape` HTML-Sonderzeichen wie <, > und &.
* `ConfigParser`: lesen von Konfigurations-Dateien im Ini-Stil
* `csv`: Unterstützung für CSV-Dateien (character-separated values)
* `email`: Parsen und Zusammenbauen von E-Mails
* `fnmatch`, `glob`: Dateien nach bestimmten Mustern finden
* `gzip`, `zip`, `zlib`, `tarfile`: Unterstützung für entsprechende
Archivdateien
* `logging`: Logging-Framework (weitreichend konfigurierbar!)
* `math`, `cmath`: mathematische Operationen
* `operator`: Funktionen, die Operatoren entsprechen sowie "erfundene"
Operatoren; praktisch für List Comprehensions und
Callback-Funktionen
* `pickle`, `shelve`: Persistierung von Python-Objekten
* `profile`: Profiler für Laufzeit-Analysen
* `random`: Zufallszahlen, Auswahloperationen etc.
* `re`: reguläre Ausdrücke (ein Beispiel ist in `contents.py`)
* `shutil`: Datei-Operationen (eher High-Level, zum Beispiel
`shutil.copytree`)
* `StringIO`: Strings mit einer Schnittstelle wie bei Dateiobjekten
versehen
* `subprocess`: Aufruf externer Programme, einschließlich Lesen aus
und Schreiben in Pipes
* `time`, `datetime`, `calendar`: Zeit- und Datumsoperationen
* `threading`, `multiprocessing`: Unterstützung für Nebenläufigkeit
auf Thread- bzw. Prozessebene
* `unittest`, `doctest`: Frameworks für automatisierte Tests
* `xml`: verschiedene XML-Parser
Eingebaute Funktionen
---------------------
* Außer den in Modulen definierten Funktionen und Klassen enthält
Python einige "eingebaute" Funktion (built-ins). Hier ein paar
wichtige.
* `complex`, `float`, `int`, `str` und `unicode`, um in Objekte des
genannten Typs umzuwandeln:
print complex("17")
print float("7.7")
print int("17"), int("0xf", 16)
print str(17), str(str), type(str(17))
print unicode(17), unicode(unicode), type(unicode(17))
`str` wird auch implizit von der `print`-Anweisung und bei
Verwendung von `%s` in Format-Strings aufgerufen.
`int` kann tatsächlich auch implizit in `long` umwandeln.
Neben `str` und `unicode` erzeugt auch `repr` ein `str`-Objekt.
Im Gegensatz zu der Darstellung von `str` ist die von `repr` aber
eher "low-level" und fürs Debugging geeignet.
print str("Test")
print repr("Test")
* `range` gibt eine Liste von numerischen Werten zurück. Die Funktion
akzeptiert bis zu drei Parametern. Nähere Infos unter
http://docs.python.org/library/functions.html#range .
* `xrange` akzeptiert die gleichen Parameter, liefert aber keine
Liste, sondern ein `xrange`-Objekt. `xrange` wird üblicherweise für
Schleifen verwendet, um den Speicher für den Aufbau einer Liste
einzusparen.
* `len` gibt die Länge des Arguments zurück.
* `open(name, mode)` öffnet eine Datei. `name` ist der Dateiname,
`mode` der Modus.
- `r` ist der Default und steht für Lesen; `w` steht für Schreiben
und `a` für Anhängen.
- Ein `b` nach dem Buchstaben gibt an, dass die Datei im
"Binärmodus" geöffnet werden soll.
- Normalerweise werden Dateien im Textmodus geöffnet, das heißt,
dass Zeilenendezeichen `\r\n` aus Dateien beim Lesen in `\n`
gewandelt werden bzw. beim Schreiben umgekehrt. Dies hat zwar nur
unter Windows einen Einfluss, aber trotzdem sollte auch unter
Unix/Linux laufender Code der Portabilität wegen bei Binärdateien
`b` verwenden.
`file` ist ein Synonym für `open`, `open` ist aber der empfohlene
Name.
* `sorted`, angewendet auf das Iterable-Argument, gibt eine sortierte
Liste der ursprünglichen Werte zurück. Dieses wird nicht verändert.
Wie die `sort`-Methode von Listen kann `sorted` ein optionales
Argument `key` verarbeiten.
* `getattr`, `setattr`, `delattr` dienen dem Lesen, Setzen, Löschen
von Attributen von Objekten. `hasattr` prüft, ob ein Objekt ein
bestimmtes Attribut besitzt. Das Besondere an diesen Funktionen ist,
dass sie einen Attributnamen als Zeichenkette verwenden. Man kann
damit auf zur Laufzeit *berechnete* Attribute von Objekten zugreifen.
* `globals` gibt ein Dictionary mit den Modul-globalen Namen und
zugeordneten Objekte zurück.
* `locals` liefert ebenfalls ein Dictionary, nämlich für die lokalen
Namen (zum Beispiel in einer Funktion).
Im Gegensatz zu dem von `globals` gelieferten Dictionary handelt es
sich beim Ergebnis von `locals` um eine "flache Kopie" (shallow
copy), so dass sich Änderungen am Rückgabewert nicht auf die
tatsächlichen lokalen Namen auswirken.
* `zip` fügt zwei oder mehrere Listen zu einer Liste von Tupeln
zusammen. Näheres siehe
http://docs.python.org/library/functions.html#zip .
* `raw_input` liest eine Zeichenkette von der Standard-Eingabe
(stdin).
* `id` gibt eine Objekt-Id zurück. Zum Test, ob zwei Objekte
dieselben sind, sollte man trotzdem den `is`-Operator verwenden,
da Objekte durch die Garbage Collection "zwischendurch" zerstört und
eine bestimmte Id dann für ein anderes Objekt vergeben werden kann.
* `abs`, `max`, `min` und `sum` berechnen Absolutbetrag, Maximum,
Minimum oder die Summe einer Liste von Werten. (Weitere mathematische
Funktionen befinden sich in den Modulen `math` und `cmath`.)
* weitere Builtin-Funktionen unter
http://docs.python.org/library/functions.html
* Spielzeit
Namensauflösung
---------------
* Wird im Code ein Name verwendet, ermittelt Python das zugehörige
Objekt nach einer definierten Such-Reihenfolge.
* Die Regel lautet LEGB:
- L - local (zum Beispiel innerhalb einer Funktion, in der der
Name steht)
- E - enclosing (in "umgebenden" Funktionen/Methoden; man kann
Funktionen schachteln!)
- G - global (im Modul-globalen Namensraum suchen)
- B - builtin (nach Builtin-Funktionen oder ein anderen
Builtin-Objekten suchen)
* zum besseren Verständnis:
# Modul mein_modul.py
G = 1 # Modul-global
def aeussere_funktion(liste):
E = liste # enclosing
def innere_funktion():
L = 3 # local
return L + E + len(E) # len wird in den Builtins gefunden
return innere_funktion
* Soll von einer Funktion aus ein Modul-globaler Name angesprochen
werden, muss die `global`-Anweisung verwendet werden:
# Modul-Namensraum
wert = 1
def f():
global wert # Ohne `global` würde nur ein lokaler Wert
wert = 2 # innerhalb der Funktion gesetzt werden.
f()
Datei-Objekte
-------------
* Datei-Objekte werden mit der `open`-Funktion erzeugt (s. o.). Es
folgen die (meines Erachtens) wichtigsten Methoden.
* `__iter__` und `next` werden normalerweise nicht direkt verwendet,
sondern implizit, um über die Zeilen einer Textdatei zu iterieren:
fobj = open("example.py")
try:
for line in fobj:
print line,
finally:
fobj.close()
Anmerkung: Der obige Code lässt sich mit der `with`-Anweisung
(vorhanden ab Python 2.5) kürzer schreiben:
with open("example.py") as fobj:
for line in fobj:
print line,
* `close` schließt eine Datei (s. o.)
* `readlines` liefert eine Liste aller Zeilen (ab der Stelle, bis zu
der früher gelesen wurde) aus der Datei. Die Zeilen-Strings enden
mit einem `\n`.
* `read` liest den Inhalt der noch "verbleibenden" Datei in einen
einzigen String. Mit einem optionalen Argument kann man die Anzahl
der maximal zu lesenden Bytes(!) bestimmen.
* `write` schreibt einen Byte-String in die Datei. Dazu muss sie zum
Schreiben geöffnet sein. `writelines` verhält sich ähnlich wie
eine Mischung von `readlines` und `write`: das Argument ist eine
Liste von Zeichenketten. Symmetrisch zu `readlines` müssen die
Zeilenendezeichen `\n` bereits vorhanden sein.
Übung
-----
Erweitern Sie das Ergebnis der vorherigen Übung, indem die Argumente
zeilenweise aus einer Datei gelesen werden. Schreibe eine Datei, die
ebenfalls zeilenweise die Ergebnisse erhält.
Wenn also die Eingangsdatei so aussieht:
0
1
5
soll die Ergebnisdatei hinterher so aussehen:
1
1
120
Eine mögliche Lösung:
# encoding: UTF-8
import fakultaet
# Dateien werden durch die `with`-Anweisungen automatisch geschlossen,
# sonst müssten sie explizit geschlossen werden.
with open("fakultaet_eingabe.txt") as eingabe:
with open("fakultaet_ausgabe.txt", 'w') as ausgabe:
for line in eingabe:
argument = int(line)
ergebnis = fakultaet.fakultaet(argument)
ausgabe.write("%d\n" % ergebnis)
Objektorientierte Programmierung (OOP)
--------------------------------------
* Überblick: Wer von den Anwesenden hat schon objektorientiert
programmiert?
* Objektorientierung ist einfacher am Beispiel zu erklären als zu
beschreiben. Hier trotzdem ein Versuch. ;-)
* *Objekte* sind ein Hilfsmittel für das Software-Design. Sie
repräsentieren "Dinge".
* Objekte haben so genannte *Attribute*, die den aktuellen Zustand
beschreiben und *Operationen* (auch *Methoden* genannt), die etwas
mit dem Objekt tun können oder Daten aus den Eigenschaften des
Objekts erzeugen können.
* In den meisten Programmiersprachen, auch in Python, werden Objekte
aus einer "Vorlage", einer *Klasse* erzeugt.
* Beispiel:
class Person(object):
"""`Person` beschreibt eine Person."""
def __init__(self, vorname, nachname):
self.vorname = vorname
self.nachname = nachname
def name(self):
return "%s %s" % (self.vorname, self.nachname)
def verheiraten(self, neuer_nachname):
self.nachname = neuer_nachname
def __str__(self):
# besondere Methode, gibt einen String zurück; wird
# implizit von `print` verwendet
return self.name()
willi = Person("Willi", "Wusel")
print type(willi)
# `willi.__class__` ist Willis Datentyp.
print willi.__class__
# `willi.__class__.__name__` ist ein String.
print willi.__class__.__name__
print
# `print` druckt den von `name` zurückgegebenen String.
print willi.name()
# `print` ruft implizit `__str__` auf, um das Objekt zu drucken.
print willi
willi.verheiraten("Schmidt")
print willi
Ein paar wichtige Punkte ...
* Im Gegensatz zur allgemeinen Terminologie in der objektorientierten
Programmierung sind in Python auch Methoden Attribute, nur eben
aufrufbare.
* Alle Attribute sind zugänglich und veränderbar. Es gibt im Gegensatz
zu manchen anderen OOP-Sprachen keine "protected" oder "private"
Attribute. (Es gibt nur *Konventionen* wie `_meine_sache`, s. o.)
class Person(object):
"""`Person` beschreibt eine Person."""
# Konstruktur
def __init__(self, vorname, nachname):
self.vorname = vorname
self.nachname = nachname
def name(self):
return "%s %s" % (self.vorname, self.nachname)
def verheiraten(self, neuer_nachname):
self.nachname = neuer_nachname
# Besondere Methode, gibt einen String zurück; wird
# implizit von `print` verwendet.
def __str__(self):
return self.name()
willi = Person("Willi", "Wusel")
willi.nachname = "Schulze"
print willi
def anonymer_name(): # Methode des *Objekts*, kein `self`;
return "<anonym>" # "bound method"
willi.name = anonymer_name
print willi
# Man kann auch die Klasse statt des Objekts verändern.
def anonymer_name(self): # Methode der *Klasse*, mit `self`;
return "<anonym>" # "unbound method"
Person.name = anonymer_name
stefan = Person("Stefan", "Schwarzer")
print stefan
*Achtung* Dass etwas *möglich ist* heißt nicht, dass man es machen
muss. :-) Der Austausch von Methoden von Laufzeit ist auch eher die
Ausnahme in Python-Programmen, normal ist aber das Hinzufügen von
nicht-aufrufbaren Attributen (Zahlen, Strings, Listen etc.).
* Jede in einer Klasse definierte Methode hat `self` als erstes
Argument (ausgenommen bei Klassen-Methoden und statischen Methoden,
die ich hier nicht behandle). `self` ist im Moment des Aufrufs das
jeweilige Objekt.
* Wie in anderen objektorientierten Sprachen ist Vererbung möglich,
das heißt einer Ausgangsklasse (*Basisklasse*) werden Attribute
hinzugefügt. Die neue Klasse nennt man *abgeleitete Klasse*. Ein
Beispiel:
class Person(object):
"""`Person` beschreibt eine Person."""
# Konstruktur
def __init__(self, vorname, nachname):
self.vorname = vorname
self.nachname = nachname
def name(self):
return "%s %s" % (self.vorname, self.nachname)
def verheiraten(self, neuer_nachname):
self.nachname = neuer_nachname
# Besondere Methode, gibt einen String zurück; wird
# implizit von `print` verwendet.
def __str__(self):
return self.name()
class Vortragender(Person):
def __init__(self, vorname, nachname):
# Konstruktor der Basisklasse aufrufen.
super(Vortragender, self).__init__(vorname, nachname)
self.thema = "<unbekannt>"
def vortrag_halten(self, thema):
self.thema = thema
print "%s hält einen Vortrag über %s." % (self.name(), thema)
def __str__(self):
name = super(Vortragender, self).__str__()
return '%s mit Thema "%s"' % (name, self.thema)
stefan = Vortragender("Stefan", "Schwarzer")
stefan.vortrag_halten("Python")
print stefan
* Vererbung sollte nur benutzt werden, wenn die Objekte der
abgeleiteten Klasse auch für Objekte der Basisklasse stehen könnten.
Man sollte also *nicht* von einer Klasse ableiten, nur um in der neuen
Klasse die Attribute der Basisklasse verwenden zu können. In diesem
Fall greift man lieber zur *Aggregation*, das heißt, man nimmt
Objekte der einen Klasse als Attribute in eine andere Klasse auf.
Beispiel:
class Rad(object):
def aufpumpen(self):
print "Rad aufpumpen ..."
class Pkw(object):
def __init__(self):
self.raeder = [Rad() for i in xrange(4)]
def wartung(self):
for rad in self.raeder:
rad.aufpumpen()
pkw = Pkw()
pkw.wartung()
Spezielle Methoden
------------------
* Wie bereits gesehen, können Klassen spezielle Methoden besitzen, die
das Verhalten bestimmter Anweisungen und Funktionen von Python
beeinflussen. Beispiele sind `__init__` und `__str__`. Hier ein paar
weitere solcher Methoden ...
* `__call__` definiert das Verhalten von `obj(...)`
* `__len__` definiert `len(obj)`
* `__getattr__`, `__setattr__` und `__delattr__` beeinflussen
Ausdrücke und Anweisungen wie
obj.attr # ruft __getattr__
obj.attr = wert # ruft __setattr__
del obj.attr # ruft __delattr__
* `__getitem__`, `__setitem__`, `__delitem__` steuern das Verhalten von
obj[index]
obj[index] = wert
del obj[index]
* `__contains__` definiert `wert in obj`
* `__repr__`: wird implizit von der eingebauten Methode `repr`
aufgerufen, oder wenn in einem Format-String `%r` vorkommt
* `__unicode__` wird aufgerufen, wenn `unicode` auf das Objekt
angewendet wird
* `__del__`: wird aufgerufen, wenn das Objekt vom Garbage Collector
gelöscht wird
* `__lt__`, `__le__` etc.: steuern das Ergebnis von
Vergleichsoperatoren (hier `<` und `<=`)
* `__add__`, `__sub__` und viele mehr legen das Verhalten bei
Anwendung mathematischer und anderer Operatoren fest
* `__nonzero__` legt den Wahrheitswert eines Objekts fest und wird
zum Beispiel implizit von `bool`, `if` und `while` verwendet
* Eine ausführliche Liste befindet sich unter
http://docs.python.org/reference/datamodel.html#special-method-names .
Übung
-----
Leiten Sie von der Klasse `Person` ab und fügen Sie eine Methode
`gehe` hinzu. Diese Methode soll eine Objektvariable (= Instanzvariable)
`tempo` setzen. In der Ausgabe von `print person` soll auch
erscheinen, welches Tempo die Person gerade hat.
Teste die Klasse mit folgendem Code:
willi = BeweglichePerson("Willi", "Wusel")
print willi.tempo # sollte 0 ausgeben
willi.gehe(3) # sollte das Tempo auf 3 km/h setzen
print willi.tempo # sollte 3 ausgeben
print willi # sollte das aktuelle Tempo enthalten
Eine mögliche Lösung:
class Person(object):
"""`Person` beschreibt eine Person."""
# Konstruktur
def __init__(self, vorname, nachname):
self.vorname = vorname
self.nachname = nachname
def name(self):
return "%s %s" % (self.vorname, self.nachname)
def verheiraten(self, neuer_nachname):
self.nachname = neuer_nachname
# Besondere Methode, gibt einen String zurück; wird
# implizit von `print` verwendet.
def __str__(self):
return self.name()
class BeweglichePerson(Person):
def __init__(self, vorname, nachname):
super(BeweglichePerson, self).__init__(vorname, nachname)
self.tempo = 0.0
def gehe(self, tempo):
self.tempo = float(tempo)
def __str__(self):
name = super(BeweglichePerson, self).__str__()
return "%s geht mit %s km/h." % (name, self.tempo)
willi = BeweglichePerson("Willi", "Wusel")
print willi.tempo # sollte 0 ausgeben
willi.gehe(3) # sollte das Tempo auf 3 km/h setzen
print willi.tempo # sollte 3 ausgeben
print willi # sollte das aktuelle Tempo enthalten
Übung
-----
Verwenden Sie das Modul `urllib`, um eine beliebige HTML-Seite zu
holen. Benutzen Sie dann das Modul `re` oder Zeichenketten-Operationen,
um die HTTP-Links innerhalb der Seite zu ermitteln und anschließend
zeilenweise auszugeben. Selbst, wenn Sie bisher keine regulären
Ausdrücke kennen, kommen Sie evtl. mit dem Code in `contents.py`
weiter.
Für die Übung ist es nicht nötig, zu unterscheiden, ob die URLs
innerhalb von Links (`a`-Tags) vorkommen oder nicht.
Nutzen Sie Funktionen, Klassen oder Methoden, um den Code
übersichtlich zu strukturieren.
Hier zur Unterstützung ein paar Links:
* `urllib`: http://docs.python.org/library/urllib.html#module-urllib
* `re`: http://docs.python.org/library/re.html#module-re
* gültige Zeichen in einem URL: http://www.ietf.org/rfc/rfc2396.txt
Der Einfachheit halber gehen Sie bitte davon aus, dass ein URL nach
dem Beginn `http://` folgende Zeichen enthalten darf:
- Groß- und Kleinbuchstaben aus dem ASCII-Zeichensatz
- Ziffern
- `; / ? : @ & = + $ , - _ . ! ~ * ' ( ) %`
*Optionale* Erweiterungen, um die Übung interessanter zu machen ;-)
* Sortieren Sie die URLs vor der Ausgabe alphabetisch.
* Entfernen Sie doppelte URLs, so dass kein URL mehrfach ausgegeben
wird.
* Übergeben Sie den auszulesenden URL per Kommandozeile.
Eine mögliche Lösung:
import os
import re
import string
import sys
import urllib
URL = "http://sschwarzer.com/publications"
VALID_URL_CHARS = string.ascii_letters + string.digits + \
";/?:@&=+$,-_.!~*'()%"
def url_regex():
"""Return a regular expression for matching URLs."""
return re.compile(r"http://[%s]+" % re.escape(VALID_URL_CHARS))
def find_urls(text):
"""Return a list of URL contained in the text `text`."""
regex = url_regex()
return regex.findall(text)
def get_text(url):
"""Return the text found at the URL `url`."""
fobj = urllib.urlopen(url)
try:
text = fobj.read()
finally:
fobj.close()
return text
def print_urls(url_list):
"""Print each of the URLs in the list `url_list` to stdout."""
# Remove duplicates.
url_list = list(set(url_list))
for url in sorted(url_list):
print url
def main(url):
"""Print links in URL `url`."""
text = get_text(url)
urls = find_urls(text)
print_urls(urls)
if __name__ == '__main__':
# Make this runnable via `example.py`.
main(URL)
sys.exit()
# Get URL from command line.
try:
url = sys.argv[1]
except IndexError:
# `sys.argv[0]` contains the script name.
print "Usage: %s <url>" % os.path.basename(sys.argv[0])
sys.exit(1)
main(url)
In der Praxis würde man das Programm wohl nicht derart weit aufteilen,
ich möchte hier nur ein paar Anregungen für "Trennstellen" geben.
Python-"Philosophie"
--------------------
* einige Tipps bekommt man mit
import this
* EAFP statt LBYL (EAFP = "it's easier to ask forgiveness than
permission", LBYL = "look before you leap")
Beispiel:
# LBYL
if os.path.exists(filename):
fobj = open(filename)
...
# EAFP (Python-typisch)
try:
fobj = open(filename)
...
except IOError:
...
* Duck Typing ("if it walks like a duck, swims like a duck and quacks
like a duck, it must be a duck")
Der Ansatz meint, dass zwei Objekte, die eine ähnliche Schnittstelle
bieten sollen, nicht von Klassen stammen müssen, die von einer
gemeinsamen Basisklasse abgeleitet sind. Ein Beispiel macht es
klarer.
Zuerst ein "Java-artiger" Ansatz:
class A(object):
def gehe(self, tempo):
raise NotImplementedError("gehe ist undefiniert")
class B(A):
def gehe(self, tempo):
...
class C(A):
def gehe(self, tempo):
...
Python-typisch (Duck Typing):
class B(object):
def gehe(self, tempo):
...
class C(object):
def gehe(self, tempo):
...
Ein bekanntes Beispiel aus der Python-Bibliothek sind die Klassen
`file` und `StringIO`, die zwar viel gemeinsam haben, aber nicht
voneinander oder einer gemeinsamen Basisklasse ableiten.
Ausblick
--------
Einige Themen, die hier nicht behandelt wurden:
* Mehrfach-Vererbung und Mixins
class A(object):
pass
class B(object):
pass
class C(A, B):
pass
- http://www.python.org/download/releases/2.2.3/descrintro/
* Generatoren und Generator-Ausdrücke
def even_numbers(max_number):
for i in xrange(0, max_number+1, 2):
yield i
print type(even_numbers)
print type(even_numbers(10))
for i in even_numbers(10):
print i
even_numbers = (i for i in xrange(0, 10, 2))
print even_numbers
print type(even_numbers)
print list(even_numbers)
- http://docs.python.org/glossary.html#term-generator
- http://docs.python.org/library/itertools.html#module-itertools
* Dekoratoren
def print_name(func):
def new_func(*args, **kwargs):
print func.__name__
return func(*args, **kwargs)
# Besser functools.wrap benutzen.
new_func.__name__ = func.__name__
new_func.__doc__ = func.__doc__
return new_func
@print_name
def example_func(max_n):
return range(max_n)
print example_func(5)
- http://docs.python.org/glossary.html#term-decorator
- http://docs.python.org/reference/compound_stmts.html#function
- http://docs.python.org/library/functools.html#module-functools
* Propertys
class A(object):
def __init__(self):
self.__x = None
def _get_x(self):
print "Get x"
return self.__x
def _set_x(self, value):
print "Set x"
self.__x = value
x = property(_get_x, _set_x)
a = A()
print a.x
a.x = 7
print a.x
- http://www.python.org/download/releases/2.2.3/descrintro/
- http://docs.python.org/reference/datamodel.html#implementing-descriptors
* Metaklassen (werden allerdings auch in Produktionscode kaum genutzt)
class A(type):
def __new__(new_class, name, bases, dict_):
special = ['__init__', '__module__', '__metaclass__']
for key in dict_:
if key in special:
continue
if not key.startswith("example_"):
raise TypeError(
"attribute name '%s' doesn't start with \"example_\"" %
key)
return type.__new__(new_class, name, bases, dict_)
class B(object):
__metaclass__ = A
def __init__(self):
print "We're fine."
def example_test(self):
print "Example"
print "alles ok soweit"
class C(B):
def forbidden(self):
pass
- http://docs.python.org/glossary.html#term-metaclass
- http://docs.python.org/reference/datamodel.html#metaclasses
* Ferner:
- Deskriptoren
http://www.python.org/download/releases/2.2.3/descrintro/
- Coroutinen
http://docs.python.org/reference/expressions.html#yield-expressions
Anhang: Ausführen der Programm-Schnipsel aus GVim
-------------------------------------------------
* Das folgende Makro zum Ausführen von Code reicht vom allein
stehenden `.` bis zum allein stehenden `..`, enthält also zwei
Leerzeilen am Ende.
?^\.$
jV/^\.\.
k:w !./example.py
* Den Text-Bereich markieren und mit "ey als Makro e speichern.
* Sofern
- `example.py` im aktuellen Verzeichnis liegt,
- `gnome-terminal` installiert ist und
- darin ein Profil "Talk" angelegt ist,
kann man nun einen Code-Schnipsel, innerhalb dessen der Cursor
steht, durch Drücken von @e ausführen.