Eine Programmiersprache
Merkmale der Programmiersprache Python:
hoher Abstraktionsgrad (“high level”): viele Mechanismen, Konzepte, Datenstrukturen etc. sind in der Sprache “eingebaut” und müssen nicht selbst implementiert werden
umfangreiche Standardbibliothek (Funktionen und Module, die in jeder Python-Installation vorhanden sein müssen)
Merkmale von CPython:
Python-Code wird “direkt” ausgeführt, d.h. muss nicht vom Benutzer kompiliert werden (wird vom Interpreter aber intern in “Bytecode” übersetzt)
interaktive Ausführung möglich
kann durch C-Code erweitert und in C-Programme eingebaut werden
Es gibt zwei Sprachversionen, die nicht vollständig kompatibel sind:
Python 2: Die letzte Version war 2.7 und ist 2010 erschienen.
Installiert unter dem Namen python
.
$ python
Python 2.7.9 (default, Jun 29 2016, 13:08:31)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
Python 3: Die erste Version 3.0 ist 2008 erschienen, die aktuellste Version (seit 2016) ist 3.6.
Installiert unter dem Namen python3
(im CIP-Pool nur Version 3.4).
$ python3
Python 3.4.2 (default, Oct 8 2014, 10:45:20)
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Python 2 wird zwar noch “gepflegt”, aber neue Features werden nur noch zu Python 3 hinzugefügt.
Alles hier gezeigte bezieht sich auf Python 3.
python3
ohne Argumente startet interaktive Sitzung (“Python-Shell”)
>>>
exit()
oder Ctrl-D
help
Eingabe eines Ausdrucks wertet diesen aus und zeigt das Ergebnis an
>>> 3 + 4
7
>>> 17 > -5
True
#
für Kommentare (egal ob interaktiv oder nicht)
>>> 24 * 60 # Minuten am Tag
1440
Alles ab dem #
-Zeichen bis zum Ende der Zeile wird vom Interpreter ignoriert.
Typ int
5
, 102
, -135876
0b
: 0b111
→ 70o
: 0o21
→ 170x
: 0x2F
→ 47keine Beschränkung des Werts: 999 ** 999
ist kein Problem (**
: Potenz)
Typ float
Eingabe mit .
: 1.5
, -0.123476
Eingabe in wissenschaftlicher Notation: 1e3
→ 1000.0; 123e-5
→ 0.00123
Wertebereich und Genauigkeit beschränkt
>>> 0.1 + 0.2
0.30000000000000004
Hier die Erläuterung.
(Es gibt aber in der Standardbibliothek ein Modul zum exakten Rechnen mit Kommazahlen, z.B. für Finanzen etc.)
explizite Umwandlung in Ganzzahl inkl. Runden Richtung 0:
>>> int(5.3)
5
>>> int(5.8)
5
>>> int(-5.3)
-5
explizite Umwandlung von Ganzzahl:
>>> float(3)
3.0
+
, -
, *
: wie erwartet/
, //
s.u.%
: Modulo (123 % 10
→ 3
)**
: Potenz (3 ** 2
→ 9
)Es gelten die üblichen Rechenregeln. Im Zweifel oder um die Rangfolge von Operatoren zu überstimmen, können Klammern ()
verwendet werden. Die Anzahl Leerzeichen um die Operatoren spielt keine Rolle (üblicherweise ein Leerzeichen):
>>> 2 * 3 + 5
11
>>> 2 * (3 + 5)
16
>>> 2 ** 3 * 4 # 8 * 4
32
>>> 2 ** (3 * 4) # 2 ** 12
4096
Es gibt zwei Divisionsoperatoren:
/
ist Fließkommadivision. Ergebnis immer float
:
3 / 5
→ 0.6
//
ist Ganzzahldivision: rundet auf nächste kleinere ganze Zahl ab (Richtung −∞). Ergebnis int
wenn beide Operanden int
, sonst float
):
3 // 5
→ 0
-3 // 5
→ -1
-3.0 // 5
→ -1.0
Das Modul math
aus der Standardbibliothek enthält mathematische Konstanten und Funktionen (Trigonometrie, Logarithmen, etc.):
>>> import math # lädt das Modul
>>> math.pi
3.141592653589793
>>> math.exp(-1)
0.36787944117144233
>>> math.log(2.71)
0.9969486348916096
>>> math.cos(3.14)
-0.9999987317275395
Meistens will man Zwischenergebnisse speichern, um sie später weiterzuverwenden oder um Ausdrücke zu vereinfachen.
Durch den Zuweisungsoperator =
gibt man einem Objekt (momentan kennen wir nur Zahlen) einen Namen:
>>> kapital = 1249
>>> zinssatz = 0.75 / 100 # Prozent
(es sind auch Großbuchstaben in Variablennamen erlaubt, üblicherweise schreibt man sie aber klein)
>>> zinsen = kapital * zinssatz # hier keine Ausgabe, da kein
# "Ausdruck" (expression) sondern eine
# "Anweisung" (statement)
>>> kapital + zinsen
1258.3675
In Python ist alles ein Objekt. Jedes Objekt hat
Die Identität eines Objekts wird festgelegt, wenn das Objekt erzeugt wird und ändert sich danach nicht mehr.
Der Typ eines Objekts bestimmt, welche Werte das Objekt annehmen kann und welche Operationen mit dem Objekt möglich sind. Der Typ eines Objekts ändert sich ebenfalls nicht mehr, sobald das Objekt erzeugt wurde.
Abhängig vom Typ kann der Wert eines Objekts verändert werden oder nicht. Objekte bzw. Typen, bei denen das Ändern des Werts möglich ist, heißen mutable, die anderen heißen immutable.
Die verschiedenen Zahlentypen sind z.B. immutable.
(Mehr dazu hier.)
Die Anweisung kapital = 1249
bedeutet:
Dem Objekt 1249
(vom Typ int
) wird der Name kapital
gegeben.
Oder: Der Name kapital
“verweist” auf das int
-Objekt 1249
.
Hinweis: Andere Programmiersprachen haben ein anderes Datenmodell, z.B. heißt in den Sprachen C oder C++ die Anweisung kapital = 1249
: Der Speicherplatz für ein int
mit dem Namen kapital
wird mit dem Wert 1249 belegt.
Im Datenmodell von Python bedeutet das:
Beispiel:
>>> kapital = 1249
>>> geld = kapital
Sowohl kapital
als auch geld
verweisen jetzt auf 1249.
>>> geld
1249
>>> kapital
1249
Es ist dasselbe Objekt (id
gibt die Identität eines Objekts aus):
>>> id(kapital)
140331518656464
>>> id(geld)
140331518656464
Wenn man jetzt den Namen kapital
neu vergibt:
>>> kapital = 398.76
hat das keine Auswirkung auf den Namen geld
: geld
verweist weiterhin auf dasselbe int
-Objekt wie zuvor, aber kapital
verweist jetzt auf ein anderes float
-Objekt:
>>> geld
1249
>>> id(geld)
140331518656464
>>> kapital
398.76
>>> id(kapital)
140331517917136
Man kann auch mehrere Namen gleichzeitig vergeben:
>>> a, b = 3, 5
>>> a
3
>>> b
5
Somit können Namen ohne “temporäre Variable” einfach vertauscht werden:
>>> a, b = b, a
>>> a
5
>>> b
3
Anstatt die Anweisungen einzeln einzutippen, kann man sie auch in einer Datei speichern und diese als “Skript” oder “Programm” ausführen.
Im Gegensatz zum interaktiven Modus werden Ausdrücke nicht automatisch ausgegeben! Um das Ergebnis der Berechnung zu sehen, muss man es explizit auf die Standardausgabe schreiben. Das geht am einfachsten mit der Funktion print
:
Beispiel: Datei zinsen.py
kapital = 1249
zinssatz = 0.75e-2 # Prozent in wissenschaftlicher Notation
zinsen = kapital * zinssatz
# Leerzeilen und Kommentare werden ignoriert
print(kapital + zinsen) # keine Ausgabe ohne print
Ruft man von der Shell den Python-Interpreter mit dem Dateinamen als Argument auf, liest er die darin enthaltenen Anweisungen, führt sie aus und beendet sich danach wieder:
$ python3 zinsen.py
1258.3675
Neben den Zahlen ein weiterer grundlegender Datentyp (Verwendung für “Text”): str
.
Folgende Dinge sind z.B. Strings:
stdin
) oder aus Dateien gelesen werdenstdout
) oder in Dateien geschrieben werdenStrings werden mit Anführungszeichen eingegeben (einfache '
oder doppelte "
).
(auf der deutschen Tastatur: '
ist auf der Taste #
, nicht rechts von ß
)
Beispiele:
>>> print('Hallo Welt!')
Hallo Welt!
>>> print("Wie geht's?")
Wie geht's?
>>> print('Er heißt "Fritz".')
Er heißt "Fritz".
Bestimmte Sonderzeichen werden als Kombination mit \
beschrieben:
>>> print('Ein\nZeilenumbruch')
Ein
Zeilenumbruch
>>> print('Ein\tTabulator')
Ein Tabulator
>>> print('Erste\tZweite Spalte')
Erste Zweite Spalte
Für längere Texte mit mehreren Zeilen kann man auch dreifach-Anführungszeichen ('''
oder """
) benutzen:
>>> print('''Erste Zeile)
... Zweite Zeile''')
Erste Zeile
Zweite Zeile
(...
ist der Prompt, falls eine Eingabe über eine Zeile hinaus geht)
Mehrere Strings können mit +
aneinandergehängt werden:
>>> a = 'Hallo'
>>> b = 'Welt'
>>> a + ' ' + b
'Hallo Welt'
Ein String kann mit *
vervielfältigt werden:
>>> 3 * 'Ha'
'HaHaHa'
Objekte vom Typ str
sind immutable. Daher wird beim aneinanderhängen oder “multiplizieren” von Strings immer ein neues Objekt erzeugt, nicht das bestehende Objekt verändert.
int(x)
wandelt ein beliebiges Objekt x
in eine Ganzzahl um, falls möglich:
>>> int(5.6) # float -> int
5
>>> int('23') # str -> int
23
>>> int('20', 16) # Basis 16 anstatt Basis 10
32
>>> int('hallo') # Fehler
float(x)
wandelt ein beliebiges Objekt x
in eine Fließkommazahl um, falls möglich:
>>> float(5) # int -> float
5.0
>>> float('23.4') # str -> float
23.4
>>> float('hallo') # Fehler
str(x)
wandelt ein beliebiges Objekt x
in seine Textdarstellung um, falls möglich:
>>> str(5) # int -> str
'5'
>>> str(3.4) # float -> str
'3.4'
Die Funktion print
wandelt Objekte automatisch in Strings um, falls möglich. Außerdem fügt sie zwischen mehrere Objekte (mit Komma getrennt) automatisch Leerzeichen ein (und am Ende einen Zeilenumbruch):
>>> kapital = 238475
>>> print('Das Kapital ist', kapital, '.')
Das Kapital ist 238475 .
Für mehr Kontrolle über die Formatierung:
>>> print('Das Kapital ist {}.'.format(kapital))
Das Kapital ist 238475.
>>> print('Pi ist ungefähr {:.2f}.'.format(math.pi))
Pi ist ungefähr 3.14.
Die Dokumentation von format
ist hier.
Mit dem []
-Operator greift man auf einzelne Zeichen eines Strings an einer bestimmten Position (Index) zu. Das erste Zeichen hat den Index 0:
>>> s = 'Hallo Welt'
>>> s[0]
'H'
>>> s[1]
'a'
Auf eine Position zuzugreifen, die es nicht gibt, erzeugt eine Fehlermeldung:
>>> s[15]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
Die Anzahl der Zeichen (“Länge”) eines Strings bekommt man mit der len
-Funktion:
>>> len(s)
10
Der größte gültige Index wäre also 9 (nicht 10).
(Ein “Zeichen” ist auch ein String mit der Länge 1.)
Mit negativen Indizes wird von hinten gezählt:
>>> s[-1] # letztes Zeichen
't'
>>> s[-10] # erstes Zeichen
'H'
>>> s[-11]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
H a l l o ' ' W e l t
0 1 2 3 4 5 6 7 8 9
-10 -9 -8 -7 -6 -5 -4 -3 -2 -1
Abschnitte (engl. slice) eines Strings bekommt man auf ähnliche Weise:
>>> s[:5] # die ersten 5 Zeichen
'Hallo'
>>> s[-4:] # die letzten 4 Zeichen
'Welt'
>>> s[2:7] # die ersten 7 ohne die ersten 2
'llo W'
>>> s[:] # alles
'Hallo Welt'
H a l l o ' ' W e l t
0 1 2 3 4 5 6 7 8 9 10
-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0
Optional: Schrittweite
>>> s[::2] # jedes 2. Zeichen
'HloWl'
>>> s[::-1] # rückwärts
'tleW ollaH'
Ob ein String in einem anderen enthalten ist, bekommt man mit dem in
-Operator heraus:
>>> 'a' in s
True
>>> 'Welt' in s
True
>>> 'x' in s
False
Speziell: Am Anfang oder am Ende?
>>> s.startswith('Hallo')
True
>>> s.endswith('Hallo')
False
>>> s.endswith('Welt')
True
Wo befindet sich ein Teilstring?
>>> s.index('H')
0
>>> s.index('l') # der erste Treffer zählt
2
>>> s.index('Welt')
6
>>> s.index('Erde')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
(startswith
, endswith
und index
sind “Methoden” eines String-Objekts)
(compound statements)
Bisher wurde eine Anweisung durch das Ende der Zeile abgeschlossen, z.B. eine Zuweisung eines Namens mit =
oder print
.
Durch bestimmte Schlüsselwörter können mehrere Anweisungen zu einer zusammengesetzten Anweisung gruppiert werden:
Mit if
wird eine Gruppe von Anweisungen (oder nur eine einzelne Anweisung) nur dann ausgeführt, wenn eine Bedingung erfüllt ist:
if x >= 3:
print('erstens')
print('zweitens')
if x > 10:
print('drittens')
print('viertens')
erstens
wird nicht ausgegeben, wenn x
kleiner als 3 istzweitens
wird immer ausgegebendrittens
und viertens
werden nur ausgegeben, wenn x
größer als 10 istif
muss mit einem :
endenif
-Zeileif 5 > 3:
print('hallo') # Syntax-Fehler
if True:
x = 10
print(x) # Syntax-Fehler
if 'hallo':
test = 3
print(10 * test) # Syntax-Fehler
Üblicherweise werden 4 Leerzeichen für “einmal” Einrücken verwendet.
Im interaktiven Modus ändert sich der Prompt zu ...
bis die zusammengesetzte Anweisung abgeschlossen ist:
>>> if 10 > 3:
... print('Das stimmt.')
...
Man muss noch einmal mehr die Eingabetaste drücken, um dem Interpreter mitzuteilen, dass die Anweisung abgeschlossen ist.
==
: gleicher Wert (z.B. bei Zahlen, Strings, …)!=
: verschiedener Wert>
, >=
, <
, <=
:
3 < x < 10
(x > 3
“und” x < 10
)Achtung
Es gibt auch den Operator is
. Er vergleicht die Identität zweier Objekte:
x is y
ist äquivalent zu id(x) == id(y)
.
Er ist nicht dazu geeignet, den Wert zweier Objekte zu vergleichen, denn zwei Objekte mit unterschiedlicher Identität (x is y
wäre falsch) können trotzdem den gleichen Wert haben (x == y
ist wahr).
Es gibt noch einen weiteren Datentyp “NoneType”, von dem es nur ein einziges Objekt geben kann, das immer denselben Wert hat: None
(“Nichts”). Es wird z.B. als “Platzhalter” verwendet. Aus bestimmten Gründen verwendet man x is None
(und nicht x == None
) um zu prüfen, ob es sich bei einem Objekt x
um None
handelt.
Merkregel:
x == y
None
zu vergleichen: x is None
Das Ergebnis eines Vergleichsoperators ist ein Objekt mit dem Typ bool
, das zwei verschiedene Werte haben kann:
True
ist “wahr”False
ist “falsch”Objekte mit anderen Typen haben auch einen Wahrheitswert:
None
ist “falsch”0
und 0.0
sind “falsch”, positive und negative Zahlen sind “wahr”''
) ist “falsch”, andere sind “wahr”Mit den booleschen Operatoren kann man mit Wahrheitswerten “rechnen” (Boolsche Algebra):
not x
: “wahr” wenn x
“falsch” istx and y
: “wahr”, wenn beide “wahr” sindx or y
: “wahr”, wenn einer der beiden oder beide “wahr” sindGenaugenommen:
x and y
: y
wenn x
“wahr”, sonst x
>>> 0 and 5
0
>>> 3 and 5
5
x or y
: x
wenn x
“wahr”, sonst y
>>> 0 or 5
5
>>> 3 or 5
3
Außerdem: “ternärer Operator”
x if c else y
: x
wenn c
“wahr”, sonst y
Zusammengesetzte Anweisungen können wiederum aus anderen zusammengesetzten Anweisungen bestehen:
if x > 3:
if x < 10:
print('x ist zwischen 3 und 10')
print('x ist 10 oder mehr')
Optional können mit elif
weitere Bedingungen der Reihe nach abgefragt werden. Die Anweisungen, deren Bedingung zuerst erfüllt sind, werden ausgeführt, die anderen nicht.
Ebenfalls optional können unter else
Anweisungen angegeben werden, die ausgeführt werden, wenn keine der Bedingungen unter if
und ggf. elif
erfüllt sind:
if x > 100:
print('groß')
elif x > 10: # 10 < x <= 100
print('mittel')
else: # x <= 10
print('klein')
Mit while
werden Anweisungen wiederholt (“While-Schleife”), solange eine Bedingung erfüllt ist.
Beispiel: Algorithmus, um zu berechnen, wieviele Koffer (jeder Koffer belegt 30 Einheiten “Platz”) in einen Kofferraum (bietet 100 “Platz”) passen:
“So lange noch Platz für einen Koffer ist zähle um 1 hoch und verringere den vorhandenen Platz um soviel wie ein Koffer belegt.”
In Python ausgedrückt:
platz = 100
koffer = 30
anzahl = 0
while platz > koffer:
platz = platz - koffer # oder auch kurz: platz -= koffer
anzahl = anzahl + 1 # oder auch kurz: anzahl += 1
print('Es passen {} Koffer rein, {} Platz bleibt übrig.'
.format(anzahl, platz))
(Innerhalb von geöffneten Klammern (()
, []
oder {}
) endet eine Anweisung nicht wie üblich am Ende der Zeile, sondern erst nachdem die äußerste Klammer geschlossen wird. So kann man lange Anweisungen auf mehrere Zeilen verteilen um den Code besser lesbar zu machen. Die Einrückung spielt in diesem Fall keine Rolle. Üblicherweise versucht man, Zeilen nicht länger als ca. 80 Zeichen zu machen.)
Mit der continue
-Anweisung werden die restlichen Anweisungen übersprungen und mit der nächsten Wiederholung weitergemacht.
Beispiel: Ausgabe aller geraden Zahlen bis 10. (Indem jede ungerade Zahl übersprungen wird)
x = 0
while x < 10: # continue springt hierher
x += 1
if x % 2: # ungerade
continue
print(x) # 2, 4, 6, 8, 10
Mit der break
-Anweisung wird die Schleife komplett abgebrochen:
x = 0
while True:
x += 1
if x >= 10:
break
print(x) # 1, 2, ..., 9
# break springt hierher
Neben den grundlegenden Datentypen (Ganz- und Fließkommazahlen, Strings, NoneType, Bool) gibt es in Python mehrere Datentypen, die Sammlungen von Objekten darstellen:
list
dict
tuple
set
Eine Liste wird mit []
und ,
eingegeben. In einer Liste können beliebige Objekte enthalten sein (auch andere Listen):
>>> x1 = [] # leere Liste
>>> x2 = [3, 'haus', None]
>>> x3 = [[1, 2], [3, 4]] # "Matrix"
[]
zu.len
funktioniert genauso.in
funktioniert genauso.>>> len(x1)
0
>>> len(x2)
3
>>> x2[1]
'haus'
>>> len(x3)
2
>>> x3[0]
[1, 2]
>>> x3[0][1]
2
Unterschied zu Strings:
>>> x = [1, 2, 3]
>>> x[1] = 'hallo'
>>> x
[1, 'hallo', 3]
Listen sind im Gegensatz zu Strings mutable.
Erinnerung Zuweisungsoperator =
: x[1]
ist auch ein “Name” für den String hallo
.
x[1]
war vorher das int
-Objekt 2
. Dieses wurde nicht verändert. Der “Name” x[1]
wurde von 2
auf 'hallo'
umgesetzt.
Um eine Gruppe von Anweisungen für jedes Element einer Liste auszuführen, kann man eine for
-Schleife benutzen (meistens einer while
-Schleife vorzuziehen):
>>> for name in names:
... print(name)
Es gibt verschiedene Funktionen um komplexere Iterationen zu ermöglichen:
enumerate(liste)
: Iteriert über liste
und nummeriert dabei durch (standardmäßig von 0 beginnend, aber man kann auch den Startwert angeben):
>>> for i, name in enumerate(names, 1):
... print('{}. {}'.format(i, name))
1. Peter
2. Paul
3. Mary
zip(A, B)
: Iteriert gleichzeitig über A
und B
und gibt jeweils ein Tupel bestehend aus einem Element aus A
und einem Element aus B
aus:
>>> hobbies = ['Tennis', 'Klavier', 'Lesen']
>>> for name, hobby in zip(names, hobbies):
... print(name, hobby)
Peter Tennis
Paul Klavier
Mary Lesen
Mit for
kann man ebenso über Strings iterieren:
>>> for c in 'hallo':
... print(c)
h
a
l
l
o
str(x)
wandelt eine Liste x
(wie jedes andere Objekt auch) in seine Textdarstellung um:
>>> str([1, 2, 3])
'[1, 2, 3]'
Umgekehrt passiert allerdings etwas anderes:
list(x)
iteriert über x
(falls möglich) und erzeugt eine Liste aller Elemente, die bei der Iteration herauskommen. Da man über Strings iterieren kann und dabei alle einzelnen Zeichen herauskommen, ergibt:
>>> list('[1, 2]')
['[', '1', ',', ' ', '2', ']'] # nicht [1, 2]!
Ein String kann mit der split
-Funktion in eine Liste von Teilstrings umgewandelt werden:
>>> 'hallo welt'.split() # standardmäßig wird an Leerzeichen aufgeteilt
['hallo', 'welt']
>>> 'asdf|qwer|cvbn'.split('|')
['asdf', 'qwer', 'cvbn']
Umgekehrt kann eine Liste von Strings mit join
in einen einzelnen String umwandeln:
>>> names = ['Peter', 'Paul', 'Mary']
>>> ' + '.join(names) # join ist "Methode" des Strings ', '
'Peter + Paul + Mary'
Falls die Elemente einer Liste untereinander vergleichbar sind (<
etc.):
sorted(liste)
iteriert über alle Elemente in liste
, in sortierter Reihenfolge beginnend beim kleinsten:
>>> for name in sorted(names):
... print(name)
liste
bleibt dabei unverändert.
Im Gegensatz dazu gibt es noch liste.sort()
, wobei liste
so verändert wird, dass die Einträge danach sortiert sind.
>>> names
['Peter', 'Paul', 'Mary']
>>> names.sort()
>>> names
['Mary', 'Paul', 'Peter']
Analog mit reversed
und reverse
: reversed
iteriert über eine Sammlung von Objekten in umgekehrter Reihenfolge, lässt die Sammlung aber unverändert. reverse
ändert die Sammlung, indem die Reihenfolge der Objekte umgekehrt wird.
reversed
und sorted
funktionieren auch mit Strings, aber reverse
und sort
nicht! Strings können nicht verändert werden (“immutable”), nur eine sortierte bzw. umgekehrte Kopie erzeugt werden.
Neue Elemente können an eine Liste angehängt oder an einer anderen Stelle eingefügt werden (die Liste wird dabei verändert):
>>> names.append('John') # hängt ein einzelnes Element an
>>> names
['Mary', 'Paul', 'Peter', 'John']
>>> names.insert(2, 'Albert')
>>> names
['Mary', 'Paul', 'Albert', 'Peter', 'John']
Liste vervielfältigen mit *
:
>>> names = 2 * names
Listen aneinanderhängen mit +
:
>>> x = [1, 2, 3]
>>> y = [10, 11, 12]
>>> x + y
[1, 2, 3, 10, 11, 12]
(auf deutsch: ???)
Ähnlich zur Mengen-Schreibweise in der Mathematik:
{x2|x ∈ {0, ..., 9},2x < 10}
>>> [x**2 for x in range(10) if 2 * x < 10]
[0, 1, 4, 9, 16]
Der if
-Teil ist optional.
(range(N)
iteriert über alle ganzen Zahlen von 0 bis N - 1
).
Äquivalent zu:
>>> result = []
>>> for x in A:
... if 2 * x < 10:
... result.append(x**2)
Dictionaries (dict
) sind “assoziative Arrays”, also eine Sammlung von (Schlüssel → Wert)-Paaren.
Unterschiede zu Listen und Strings:
None
Gemeinsamkeiten mit Listen und Strings:
[]
(Schlüssel anstatt Index)len
: Anzahl Einträgein
: ob der Schlüssel vorhanden istfor
-Schleife: iteriert über Schlüssel (in beliebiger Reihenfolge)Eingabe mit {}
, :
und ,
:
>>> si_prefixes = {'k': 1e3, 'M': 1e6, 'm': 1e-3, 'n': 1e-9}
>>> si_prefixes['M']
1000000.0
>>> elements = {1: 'H', 17: 'Cl', 14: 'Si'}
>>> elements[17]
'Cl'
Falls mit dem []
-Operator versucht wird, auf einen Schlüssel zuzugreifen, den es nicht gibt, wird eine Fehlermeldung erzeugt:
>>> {'a': 5}['b']
KeyError: 'b'
Als Alternative gibt es die Methode get()
, die entweder den zu einem Schlüssel gehörigen Wert zurückgibt, oder falls nicht vorhanden, einen Ersatz:
>>> {'a': 5}.get('b', 0)
0
Neue Einträge werden ebenfalls mit dem []
-Operator angelegt:
>>> len(elements)
3
>>> elements[27] = 'Co'
>>> len(elements)
4
Analog zu List comprehensions gibt es Dictionary comprehensions:
>>> {x: x**2 for x in range(5)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Beim Iterieren über ein Dictionary-Objekt kommen die Schlüssel (in beliebiger Reihenfolge) heraus:
>>> for atomic_number in elements:
... print(atomic_number, elements[atomic_number])
17 Cl
14 Si
1 H
27 Co
Um gleichzeitig über die Schlüssel und die zugeordneten Objekte zu iterieren, gibt es die Methode items()
:
>>> for atomic_number, name in elements.items():
... print(atomic_number, name)
17 Cl
14 Si
1 H
27 Co
Tupel (tuple
) sind ähnlich wie Listen Sammlungen von Objekten, die eine bestimmte Reihenfolge haben.
Wesentlicher Unterschied: Sie sind immutable und daher als Schlüssel in Dictionaries geeignet.
Eingabe mit ,
(die Klammern ()
sind nur optional)
z.B. in einem Spiel mit “Schatzkarte”:
>>> karte = {} # leeres Dictionary
>>> karte[1, 2] = 'schatz' # "1, 2" ist das Tupel
>>> for ort in [(5, 8), (10, 2)]: # Klammern zur Abgrenzung
... karte[ort] = 'falle'
Erinnerung Mehrfachzuweisung:
>>> a, b = 3, 5
3, 5
war eigentlich ein Tupel. Es wurde darüber “iteriert” und der Reihe nach die Namen vergeben.
Das funktioniert genauso mit allem anderen, worüber man iterieren kann (Listen, Strings, Dictionaries).
>>> a, b = 'xy'
>>> a
'x'
>>> b
'y'
In einer Liste kann dasselbe Objekt mehrfach enthalten sein:
>>> [1, 2, 1, 1, 5]
[1, 2, 1, 1, 5]
Im Gegensatz dazu kann in einer Menge (set
) jeder Eintrag kann nur einmal enthalten sein, und wie in einem Dictionary haben die Einträge keine feste Reihenfolge.
Mengen werden mit {}
und ,
eingegeben (ohne :
wie bei Dictionaries).
>>> {1, 2, 1, 1, 5}
{1, 2, 5}
>>> s = {1, 2, 3} # keine :
>>> d = {} # leeres Dictionary
>>> s2 = set() # leere Menge
>>> s.add(6)
>>> len(s)
4
>>> s.add(1) # schon enthalten
>>> len(s)
4
in
-Operator besonders effizient.Technik, um festzustellen, ob in einer Liste etc. Einträge doppelt vorkommen:
>>> x = [1, 2, 3, 2]
>>> len(x) == len(set(x)) # 4 == 3 ?
False
Um eine Gruppe von Anweisungen wiederzuverwenden und Programme zu strukturieren, kann man eigene Funktionen definieren.
Um eine Funktion zu verwenden, muss man sie aufrufen (engl. call) und ihr dabei je nach Funktion eine bestimmte Anzahl Argumente übergeben, die beim Ausführen der Funktion verwendet werden können. Anschließend erhält man von der Funktion einen Rückgabewert.
Die Syntax ist:
f(a, b)
f
: Name der Funktiona
und b
: Argumentef(a, b)
ist ein Ausdruck der den Rückgabewert ergibt.
(So wie 3 + 5
ein Ausdruck ist, der den Wert 8
ergibt).
Um den Rückgabewert zu verwenden, kann man ihm einen Namen zuweisen:
y = f(a, b)
Nachdem die Funktion ausgeführt wurde, bezeichnet y
den Rückgabewert.
Es sind beliebige Objekte als Argumente und Rückgabewerte möglich.
Viele Funktionen sind bereits vordefiniert oder in der Standardbibliothek enthalten:
len
>>> N = len('abc')
>>> N
3
math.sin
, math.log
, etc. aus dem Modul math
der Standardbibliothek
sum
addiert alle Einträge in einer Sammlung:
>>> x = [3, 6, 12]
>>> sum(x)
21
min
, max
gibt kleinsten/größten Eintrag einer Sammlung zurück
Liste aller vordefinierten Funktionen:
https://docs.python.org/3/library/functions.html
Übersicht über alle Module in der Standardbibliothek:
https://docs.python.org/3/library/index.html
Zum Beispiel: Modul random
für Zufallszahlen
>>> import random
>>> random.random() # Zufällige Fließkommazahl im Intervall [0, 1)
0.5623618628865356
>>> random.randint(1, 6) # Zufällige ganze Zahl zwischen 1 und 6
3
>>> random.choice('Hallo') # Ein zufälliges Element aus einer Sammlung
'a'
>>> random.sample('Hallo', 2) # Ziehe 2 ohne zurückzulegen
['a', 'o']
Manche Funktionen haben scheinbar keinen Rückgabewert, z.B. print
:
>>> x = print('hello')
hello
>>> x
>>> # Nichts
Was ist x
?
Funktionen “ohne” Rückgabewert geben in Wirklichkeit das Objekt None
zurück.
>>> x is None
True
(Wiederholung: is
vergleicht die Identität von Objekten und sollte nur in bestimmten Fällen benutzt werden. Normalerweise muss man den Vergleichsoperator ==
benutzen, um den Wert von Objekten zu vergleichen.)
“Methoden” sind eine spezielle Art von Funktion. Sie “gehören” zu einem Objekt und erhalten dieses automatisch als ein weiteres Argument:
'---'.join(['a', 'b', 'c'])
'---'
['a', 'b', 'c']
'a---b---c'
Eine Funktionsdefinition (def
) ist wie if
, while
und for
eine zusammengesetzte Anweisung mit den gleichen Syntax-Regeln:
def
-Zeile muss mit :
enden.Die Funktionsdefinition
def f(a, b):
print(a)
print(2 * b)
erzeugt eine neue Funktion mit dem Namen f
. Sie hat zwei Parameter: a
und b
.
Um die Funktion zu verwenden (“aufzurufen”), muss man ihr entsprechend der Parameterliste konkrete Objekte übergeben, die dann innerhalb der Funktion als a
und b
bekannt sind.
f(2, 5)
f(1, 'x')
ist nun dasselbe wie
print(2)
print(10)
print(1)
print('xx')
Ein Funktionsaufruf ist beendet, wenn alle Anweisungen ausgeführt worden sind (dann wird automatisch None
zurückgegeben), oder wenn die return
-Anweisung ausgeführt wurde, durch die auch optional der Rückgabewert festgelegt wird.
>>> def berechne_zinsen(kapital, zinssatz_prozent):
... zinssatz = zinssatz_prozent * 1e-2
... return kapital * zinssatz
...
>>> k = 12376
>>> berechne_zinsen(k, 0.75)
92.82
>>> for p in [0.75, 1.0, 1.25]:
... print(p, berechne_zinsen(k, p))
0.75 92.82
1.0 123.76
1.25 154.7
Eine Funktion ist auch ein Objekt, dem durch die def
-Anweisung auch ein Name (hier: berechne_zinsen
) zugewiesen wird, und kann daher wie jedes andere Objekt in einer Liste oder einem Dictionary enthalten sein (sogar als Schlüssel):
>>> berechne_zinsen
<function berechne_zinsen at 0x7f1710001668>
>>> funktionssammlung = {'z': berechne_zinsen}
>>> funktionssammlung['z'](12983746, 2.3)
298626.158
>>> trig = [math.sin, math.cos, math.tan]
>>> for f in trig:
... print(f(0.5))
...
0.479425538604
0.87758256189
0.546302489844
Namen, die innerhalb einer Funktion vergeben werden, sind außerhalb der Funktion nicht sichtbar.
>>> def bla():
... x = 5
... return x
...
>>> bla()
5
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
Es ist empfehlenswert, zu einer Funktion einen “Docstring” hinzuzufügen, der beschreibt, was die Funktion macht, und wie man sie benutzt.
def berechne_zinsen(kapital, zinssatz_prozent):
"""Berechne die Zinsen, die auf das Kapital beim angegebenen Zinssatz
(in Prozent) anfallen.
"""
zinssatz = zinssatz_prozent * 1e-2
return kapital * zinssatz
Das besondere dabei ist, dass der Docstring vom Python-Hilfesystem verarbeitet werden kann:
>>> help(zinsen)
Help on function berechne_zinsen in module __main__:
berechne_zinsen(kapital, zinssatz_prozent)
Berechne die Zinsen, die auf das Kapital beim angegebenen Zinssatz
(in Prozent) anfallen.
Noch besser ist es, Beispiele für die Benutzung der Funktion in den Docstring zu integrieren. Diese können vom Modul doctest automatisch ausgeführt und überprüft werden!
def berechne_zinsen(kapital, zinssatz_prozent):
"""Berechne die Zinsen, die auf das Kapital beim angegebenen Zinssatz
(in Prozent) anfallen.
>>> berechne_zinsen(12983746, 2.3)
298626.158
"""
zinssatz = zinssatz_prozent * 1e-2
return kapital * zinssatz
Angenommen, die Funktion berechne_zinsen
ist in der Datei zinsen.py
gespeichert, geschieht das von der Shell aus folgendermaßen:
$ python3 -m doctest zinsen.py
Eine Datei, in der Python-Code gespeichert ist, kann nicht nur als Skript ausgeführt werden (python3 <dateiname>
), sondern auch als Modul importiert werden.
Die Funktionen, die in der Datei (mit der Endung .py
) enthalten sind, werden dadurch verfügbar gemacht. Der Name des Moduls ist gleich dem Dateinamen ohne die Endung .py
:
>>> import zinsen
>>> zinsen.berechne_zinsen(12983746, 2.3)
298626.158
Um einzelne Funktionen zu importieren und das Voranstellen des Modulnamens zu vermeiden, gibt es folgende Variante:
>>> from zinsen import berechne_zinsen
>>> berechne_zinsen(12983746, 2.3)
298626.158
Die Argumente, die beim Ausführen eines Python-Programms von der Shell aus mitgegeben werden, sind innerhalb des Programms als eine Liste Strings namens argv
im Modul sys
verfügbar.
argv[0]
ist der Name des aufgerufenen Skripts, die eigentlichen Argumente sind argv[1]
, argv[2]
, etc.
Beispiel: Datei zinsen.py
import sys
def berechne_zinsen(kapital, zinssatz_prozent):
"""Berechne die Zinsen, die auf das Kapital beim angegebenen Zinssatz
(in Prozent) anfallen.
>>> zinsen(12983746, 2.3)
298626.158
"""
zinssatz = zinssatz_prozent * 1e-2
return kapital * zinssatz
k = float(sys.argv[1])
z = float(sys.argv[2])
print(berechne_zinsen(k, z))
Dann:
$ python3 zinsen.py 12983746 2.3
298626.158
Problem:
Beim Importieren wird immer der gesamte Inhalt der Datei ausgeführt. Um vermeiden, dass ein Skript ausgeführt wird, wenn es auch als Modul verwendet werden soll, gibt es folgende Technik:
def zinsen(kapital, zinssatz_prozent):
"""Berechne die Zinsen, die auf das Kapital beim angegebenen Zinssatz
(in Prozent) anfallen.
>>> zinsen(12983746, 2.3)
298626.158
"""
zinssatz = zinssatz_prozent * 1e-2
return kapital * zinssatz
if __name__ == '__main__':
# dieser Teil wird nur beim Ausführen als Skript ausgeführt,
# nicht beim Importieren als Modul
import sys
k = float(sys.argv[1])
z = float(sys.argv[2])
print(berechne_zinsen(k, z))
Die Docstrings kann man auch von der Shell aus mit dem Befehl pydoc3 <Modul>
aufrufen.
Die einfachste Möglichkeit, Informationen aus einem Programm auszugeben, ist die print
-Funktion zu benutzen.
Sie schreibt normalerweise ihre Argumente auf die Standardausgabe (siehe Einführung Linux).
Die Standardeingabe wird vom Objekt stdin
im Modul sys
repräsentiert. Man kann in einer for
-Schleife über alle Zeilen der Standardeingabe iterieren (jeweils ein String-Objekt):
import sys
for line in sys.stdin:
print(2 * line)
Speichert man diesen Code in einer Datei doppelt.py
und führt ihn von der Linux-Shell aus:
$ python3 doppelt.py
asdf
asdfasdf
hallo
hallohallo
(mit Strg-D beenden)
Um anstelle der Standardeingabe eine Datei zum Lesen zu verwenden, muss sie erst geöffnet werden. Das zeilenweise Lesen funktioniert analog. Anschließend muss die Datei wieder geschlossen werden:
f = open('datei.txt')
for line in f:
# ...
f.close() # so nicht angewöhnen, besser s.u.
Falls zwischen open
und close
ein Fehler passiert, durch den das Programm abgebrochen wird, wird die Datei u.U. nicht richtig geschlossen. Um das zu vermeiden, gibt es folgenden Mechanismus, den man sich angewöhnen sollte:
with open('datei.txt') as f:
for line in f:
# ...
Hier ist sichergestellt, dass die Datei nach dem with
-Block in jedem Fall wieder geschlossen worden ist.
Beispiel: Einlesen einer Datei zahlen.txt
mit eine Liste von Zahlen (eine Zahl pro Zeile):
5
3
7
135
In Python:
>>> zahlen = [] # leere Liste
>>> with open('zahlen.txt') as f:
... for line in f: # line ist ein String, z.B. '7'
... zahlen.append(int(line)) # wandle in Zahl um: '7' -> 7
...
>>> zahlen
[5, 3, 7, 135]
Oder auch kürzer mit einer list comprehension:
>>> with open('zahlen.txt') as f:
... zahlen = [int(line) for line in f]
>>> zahlen
[5, 3, 7, 135]
Um in eine Datei zu schreiben, muss beim Öffnen das Argument 'w'
angegeben werden (Vorsicht: eine Datei, die bereits existiert, wird so durch eine leere Datei ersetzt).
Am einfachsten schreibt man zeilenweise in die Datei, indem man die geöffnete Datei an die print
-Funktion übergibt:
with open('datei.txt', 'w') as f:
print('hallo', file=f)
Um an eine bestehende Datei anzuhängen, kann man 'a'
anstatt 'w'
benutzen. (Analog zu den Umleitungsoperatoren >>
und >
in der Linux-Shell.)