Rheinwerk Computing < openbook >

 
Inhaltsverzeichnis
1 Einleitung
2 Die Programmiersprache Python
Teil I Einstieg in Python
3 Erste Schritte im interaktiven Modus
4 Der Weg zum ersten Programm
5 Kontrollstrukturen
6 Dateien
7 Das Laufzeitmodell
8 Funktionen, Methoden und Attribute
9 Informationsquellen zu Python
Teil II Datentypen
10 Das Nichts – NoneType
11 Operatoren
12 Numerische Datentypen
13 Sequenzielle Datentypen
14 Zuordnungen
15 Mengen
16 Collections
17 Datum und Zeit
18 Aufzählungstypen – Enum
Teil III Fortgeschrittene Programmiertechniken
19 Funktionen
20 Modularisierung
21 Objektorientierung
22 Ausnahmebehandlung
23 Iteratoren
24 Kontextobjekte
25 Manipulation von Funktionen und Methoden
Teil IV Die Standardbibliothek
26 Mathematik
27 Kryptografie
28 Reguläre Ausdrücke
29 Schnittstelle zu Betriebssystem und Laufzeitumgebung
30 Kommandozeilenparameter
31 Dateisystem
32 Parallele Programmierung
33 Datenspeicherung
34 Netzwerkkommunikation
35 Debugging und Qualitätssicherung
36 Dokumentation
Teil V Weiterführende Themen
37 Anbindung an andere Programmiersprachen
38 Distribution von Python-Projekten
39 Grafische Benutzeroberflächen
40 Python als serverseitige Programmiersprache im WWW – ein Einstieg in Django
41 Wissenschaftliches Rechnen
42 Insiderwissen
43 Von Python 2 nach Python 3
A Anhang
Stichwortverzeichnis

Download:
- Beispielprogramme, ca. 464 KB

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Python 3 von Johannes Ernesti, Peter Kaiser
Das umfassende Handbuch
Buch: Python 3

Python 3
Pfeil 19 Funktionen
Pfeil 19.1 Schreiben einer Funktion
Pfeil 19.2 Funktionsobjekte
Pfeil 19.3 Funktionsparameter
Pfeil 19.3.1 Optionale Parameter
Pfeil 19.3.2 Schlüsselwortparameter
Pfeil 19.3.3 Beliebige Anzahl von Parametern
Pfeil 19.3.4 Reine Schlüsselwortparameter
Pfeil 19.3.5 Entpacken einer Parameterliste
Pfeil 19.3.6 Seiteneffekte
Pfeil 19.4 Namensräume
Pfeil 19.4.1 Zugriff auf globale Variablen – global
Pfeil 19.4.2 Zugriff auf den globalen Namensraum
Pfeil 19.4.3 Lokale Funktionen
Pfeil 19.4.4 Zugriff auf übergeordnete Namensräume – nonlocal
Pfeil 19.5 Anonyme Funktionen
Pfeil 19.6 Annotationen
Pfeil 19.7 Rekursion
Pfeil 19.8 Eingebaute Funktionen
Pfeil 19.8.1 abs(x)
Pfeil 19.8.2 all(iterable)
Pfeil 19.8.3 any(iterable)
Pfeil 19.8.4 ascii(object)
Pfeil 19.8.5 bin(x)
Pfeil 19.8.6 bool([x])
Pfeil 19.8.7 bytearray([source, encoding, errors])
Pfeil 19.8.8 bytes([source, encoding, errors])
Pfeil 19.8.9 chr(i)
Pfeil 19.8.10 complex([real, imag])
Pfeil 19.8.11 dict([source])
Pfeil 19.8.12 divmod(a, b)
Pfeil 19.8.13 enumerate(iterable)
Pfeil 19.8.14 eval(expression, [globals, locals])
Pfeil 19.8.15 exec(object, [globals, locals])
Pfeil 19.8.16 filter(function, iterable)
Pfeil 19.8.17 float([x])
Pfeil 19.8.18 format(value, [format_spec])
Pfeil 19.8.19 frozenset([iterable])
Pfeil 19.8.20 globals()
Pfeil 19.8.21 hash(object)
Pfeil 19.8.22 help([object])
Pfeil 19.8.23 hex(x)
Pfeil 19.8.24 id(object)
Pfeil 19.8.25 input([prompt])
Pfeil 19.8.26 int([x, base])
Pfeil 19.8.27 len(s)
Pfeil 19.8.28 list([sequence])
Pfeil 19.8.29 locals()
Pfeil 19.8.30 map(function, [*iterable])
Pfeil 19.8.31 max(iterable, {default, key}), max(arg1, arg2, [*args], {key})
Pfeil 19.8.32 min(iterable, {default, key}), min(arg1, arg2, [*args], {key})
Pfeil 19.8.33 oct(x)
Pfeil 19.8.34 ord(c)
Pfeil 19.8.35 pow(x, y, [z])
Pfeil 19.8.36 print([*objects], {sep, end, file, flush})
Pfeil 19.8.37 range([start], stop, [step])
Pfeil 19.8.38 repr(object)
Pfeil 19.8.39 reversed(sequence)
Pfeil 19.8.40 round(x, [n])
Pfeil 19.8.41 set([iterable])
Pfeil 19.8.42 sorted(iterable, [key, reverse])
Pfeil 19.8.43 str([object, encoding, errors])
Pfeil 19.8.44 sum(iterable, [start])
Pfeil 19.8.45 tuple([iterable])
Pfeil 19.8.46 type(object)
Pfeil 19.8.47 zip([*iterables])
 
Zum Seitenanfang

19.3    Funktionsparameter Zur vorigen ÜberschriftZur nächsten Überschrift

Wir haben bereits oberflächlich besprochen, was Funktionsparameter sind und wie sie verwendet werden können, doch das ist bei Weitem noch nicht die ganze Wahrheit. In diesem Abschnitt werden Sie drei alternative Techniken zur Übergabe von Funktionsparametern kennenlernen.

 
Zum Seitenanfang

19.3.1    Optionale Parameter Zur vorigen ÜberschriftZur nächsten Überschrift

Zu Beginn dieses Kapitels wurde die Verwendung einer Funktion anhand der Built-in Function range erklärt. Sicherlich wissen Sie aus Abschnitt 5.2.6 über die for-Schleife noch, dass der letzte der drei Parameter der range-Funktion optional ist. Das bedeutet zunächst einmal, dass dieser Parameter beim Funktionsaufruf weggelassen werden kann. Ein optionaler Parameter muss funktionsintern mit einem Wert vorbelegt sein, üblicherweise einem Standardwert, der in einem Großteil der Funktionsaufrufe ausreichend ist. Bei der Funktion range regelt der dritte Parameter die Schrittweite und ist mit 1 vorbelegt. Folgende Aufrufe von range sind also äquivalent:

  • range(2, 10, 1)
  • range(2, 10)

Dies ist interessant, denn oftmals hat eine Funktion ein Standardverhalten, das sich durch zusätzliche Parameter an spezielle Gegebenheiten anpassen lassen soll. In den überwiegenden Fällen, in denen das Standardverhalten jedoch genügt, wäre es umständlich, trotzdem die für diesen Aufruf überflüssigen Parameter anzugeben. Deswegen sind vordefinierte Parameterwerte oft eine sinnvolle Ergänzung einer Funktionsschnittstelle.

Um einen Funktionsparameter mit einem Default-Wert vorzubelegen, wird dieser Wert bei der Funktionsdefinition zusammen mit einem Gleichheitszeichen hinter den Parameternamen geschrieben. Die folgende Funktion soll je nach Anwendung die Summe von zwei, drei oder vier ganzen Zahlen berechnen und das Ergebnis zurückgeben. Dabei soll der Programmierer beim Aufruf der Funktion nur so viele Zahlen angeben müssen, wie er benötigt:

>>> def summe(a, b, c=0, d=0):
... return a + b + c + d

Um eine Addition durchzuführen, müssen mindestens zwei Parameter übergeben worden sein. Die anderen beiden werden mit 0 vorbelegt. Sollten sie beim Funktionsaufruf nicht explizit angegeben werden, fließen sie nicht in die Addition ein. Die Funktion kann folgendermaßen aufgerufen werden:

>>> summe(1, 2)
3
>>> summe(1, 2, 3)
6
>>> summe(1, 2, 3, 4)
10

Beachten Sie, dass optionale Parameter nur am Ende einer Funktionsschnittstelle stehen dürfen. Das heißt, dass auf einen optionalen kein nicht-optionaler Parameter mehr folgen darf. Diese Einschränkung ist wichtig, damit alle angegebenen Parameter eindeutig zugeordnet werden können.

 
Zum Seitenanfang

19.3.2    Schlüsselwortparameter Zur vorigen ÜberschriftZur nächsten Überschrift

Neben den bislang verwendeten sogenannten Positional Arguments (Positionsparameter) gibt es in Python eine weitere Möglichkeit, Parameter zu übergeben. Solche Parameter werden Keyword Arguments (Schlüsselwortparameter) genannt. Es handelt sich dabei um eine alternative Technik, Parameter beim Funktionsaufruf zu übergeben. An der Funktionsdefinition ändert sich nichts. Betrachten wir dazu unsere Summenfunktion, die wir im vorangegangenen Abschnitt geschrieben haben:

>>> def summe(a, b, c=0, d=0):
... return a + b + c + d

Diese Funktion kann auch folgendermaßen aufgerufen werden:

>>> summe(d=1, b=3, c=2, a=1)
7

Dazu werden im Funktionsaufruf die Parameter wie bei einer Zuweisung auf den gewünschten Wert gesetzt. Da bei der Übergabe der jeweilige Parametername angegeben werden muss, ist die Zuordnung unter allen Umständen eindeutig. Das erlaubt es dem Programmierer, Schlüsselwortparameter in beliebiger Reihenfolge anzugeben.

Es ist möglich, beide Formen der Parameterübergabe zu kombinieren. Dabei ist zu beachten, dass keine Positional Arguments auf Keyword Arguments folgen dürfen, Letztere also immer am Ende des Funktionsaufrufs stehen müssen.

>>> summe(1, 2, c=10, d=11)
24

Beachten Sie außerdem, dass nur solche Parameter als Keyword Arguments übergeben werden dürfen, die im selben Funktionsaufruf nicht bereits als Positional Arguments übergeben wurden.

 
Zum Seitenanfang

19.3.3    Beliebige Anzahl von Parametern Zur vorigen ÜberschriftZur nächsten Überschrift

Rufen Sie sich noch einmal die Verwendung der eingebauten Funktion print in Erinnerung:

>>> print("P")
P
>>> print("P", "y", "t", "h", "o", "n")
P y t h o n
>>> print("P", "y", "t", "h", "o", "n", " ", "i", "s", "t", " ",
... "s", "u", "p", "e", "r")
P y t h o n i s t s u p e r

Offensichtlich ist es möglich, der Funktion print eine beliebige Anzahl von Parametern zu übergeben. Diese Eigenschaft ist nicht exklusiv für die print-Funktion, sondern es können auch eigene Funktionen definiert werden, denen beliebig viele Parameter übergeben werden können.

Für beide Formen der Parameterübergabe (Positional und Keyword) gibt es eine Notation, die es einer Funktion ermöglicht, beliebig viele Parameter entgegenzunehmen. Bleiben wir zunächst einmal bei den Positional Arguments. Betrachten Sie dazu folgende Funktionsdefinition:

>>> def funktion(a, b, *weitere):
... print("Feste Parameter:", a, b)
... print("Weitere Parameter:", weitere)
...

Zunächst einmal werden ganz klassisch zwei Parameter a und b festgelegt und zusätzlich ein dritter namens weitere. Wichtig ist der Stern vor seinem Namen. Bei einem Aufruf dieser Funktion würden a und b, wie Sie das bereits kennen, die ersten beiden übergebenen Instanzen referenzieren. Interessant ist, dass weitere fortan ein Tupel referenziert, das alle zusätzlich übergebenen Instanzen enthält. Anschaulich wird dies, wenn wir folgende Funktionsaufrufe betrachten:

>>> funktion(1, 2)
Feste Parameter: 1 2
Weitere Parameter: ()
>>> funktion(1, 2, "Hallo Welt", 42, [1,2,3,4])
Feste Parameter: 1 2
Weitere Parameter: ('Hallo Welt', 42, [1, 2, 3, 4])

Der Parameter weitere referenziert also beim ersten Aufruf ein leeres Tupel und beim zweiten Aufruf ein Tupel, in dem alle über a und b hinausgehenden Instanzen in der Reihenfolge enthalten sind, in der sie übergeben wurden.

An dieser Stelle möchten wir die im vorangegangenen Beispiel definierte Funktion summe dahingehend erweitern, dass sie die Summe einer vom Benutzer festgelegten Zahl von Parametern berechnen kann:

>>> def summe(*parameter):
... s = 0
... for p in parameter:
... s += p
... return s

Das folgende Beispiel demonstriert die Anwendung der weiterentwickelten Funktion summe im interaktiven Modus:

>>> summe(1, 2, 3, 4, 5)
15
>>> summe(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
78

Diese Art, einer Funktion das Entgegennehmen beliebig vieler Parameter zu ermöglichen, funktioniert ebenso für Keyword Arguments. Der Unterschied besteht darin, dass der Parameter, der alle weiteren Instanzen enthalten soll, in der Funktionsdefinition mit zwei Sternen geschrieben werden muss. Außerdem referenziert er später kein Tupel, sondern ein Dictionary. Dieses Dictionary enthält den jeweiligen Parameternamen als Schlüssel und die übergebene Instanz als Wert. Betrachten Sie dazu folgende Funktionsdefinition:

>>> def funktion(a, b, **weitere):
... print("Feste Parameter:", a, b)
... print("Weitere Parameter:", weitere)

und diese beiden dazu passenden Funktionsaufrufe:

>>> funktion(1, 2)
Feste Parameter: 1 2
Weitere Parameter: {}
>>> funktion(1, 2, johannes="ernesti", peter="kaiser")
Feste Parameter: 1 2
Weitere Parameter: {'johannes': 'ernesti', 'peter': 'kaiser'}

Der Parameter weitere referenziert also ein Dictionary, das alle übergebenen Schlüsselwortparameter mit Wert enthält.

Beide Techniken zum Entgegennehmen beliebig vieler Parameter können zusammen verwendet werden, wie folgende Funktionsdefinition zeigt:

>>> def funktion(*positional, **keyword):
... print("Positional:", positional)
... print("Keyword:", keyword)
>>> funktion(1, 2, 3, 4, hallo="welt", key="word")
Positional: (1, 2, 3, 4)
Keyword: {'hallo': 'welt', 'key': 'word'}

Sie sehen, dass positional ein Tupel mit allen Positions- und keyword ein Dictionary mit allen Schlüsselwortparametern referenziert.

 
Zum Seitenanfang

19.3.4    Reine Schlüsselwortparameter Zur vorigen ÜberschriftZur nächsten Überschrift

Es ist möglich, Parameter zu definieren, die ausschließlich in Form von Schlüsselwortparametern übergeben werden dürfen. Solche reinen Schlüsselwortparameter[ 64 ](engl. keyword-only parameters) werden bei der Funktionsdefinition nach dem Parameter geschrieben, der beliebig viele Positionsargumente aufnimmt:

>>> def f(a, b, *c, d, e):
... print(a, b, c, d, e)

In diesem Fall besteht die Funktionsschnittstelle aus den beiden Positionsparametern a und b, der Möglichkeit für weitere Positionsparameter *c und den beiden reinen Schlüsselwortparametern d und e. Es gibt keine Möglichkeit, die Parameter d und e zu übergeben, außer in Form von Schlüsselwortparametern.

>>> f(1, 2, 3, 4, 5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() missing 2 required keyword-only arguments: 'd' and 'e'
>>> f(1, 2, 3, 4, 5, d=4, e=5)
1 2 (3, 4, 5) 4 5

Wie bei Positionsparametern müssen reine Schlüsselwortparameter angegeben werden, sofern sie nicht mit einem Default-Wert belegt sind:

>>> def f(a, b, *c, d=4, e=5):
... print(a, b, c, d, e)
...
>>> f(1, 2, 3)
1 2 (3,) 4 5

Wenn zusätzlich die Übergabe beliebig vieler Schlüsselwortparameter ermöglicht werden soll, folgt die dazu notwendige **-Notation nach den reinen Schlüsselwortparametern am Ende der Funktionsdefinition:

>>> def f(a, b, *args, d, e, **kwargs):
... print(a, b, args, d, e, kwargs)

Es ist auch möglich, reine Schlüsselwortparameter zu definieren, ohne gleichzeitig beliebig viele Positionsparameter zuzulassen. Dazu werden die reinen Schlüsselwortparameter in der Funktionsschnittstelle durch einen * von den Positionsparametern getrennt.

>>> def f(a, b, *, c, d):
... print(a, b, c, d)
...
>>> f(1, 2, 3, 4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 4 were given
>>> f(1, 2, c=3, d=4)
1 2 3 4
 
Zum Seitenanfang

19.3.5    Entpacken einer Parameterliste Zur vorigen ÜberschriftZur nächsten Überschrift

In diesem Abschnitt lernen Sie eine weitere Möglichkeit kennen, Parameter an eine Funktion zu übergeben. Dazu stellen wir uns vor, wir wollten mithilfe der in Abschnitt 19.3.3, »Beliebige Anzahl von Parametern«, definierten erweiterten Version der summe-Funktion die Summe aller Einträge eines Tupels bestimmen. Dazu ist momentan die folgende Notation nötig:

>>> t = (1, 4, 3, 7, 9, 2)
>>> summe(t[0], t[1], t[2], t[3], t[4], t[5])
26

Das ist sehr umständlich. Zudem laufen wir der Allgemeinheit der Funktion summe zuwider, denn die Anzahl der Elemente des Tupels t muss stets bekannt sein. Wünschenswert ist ein Weg, eine in einem iterierbaren Objekt gespeicherte Liste von Argumenten direkt einer Funktion übergeben zu können. Dieser Vorgang wird Entpacken genannt.

Das Entpacken eines iterierbaren Objekts geschieht dadurch, dass der Funktion das Objekt mit einem vorangestellten Sternchen (*) übergeben wird. Im folgenden Beispiel wird das von der eingebauten Funktion range erzeugte iterierbare Objekt verwendet, um mithilfe der Funktion summe die Summe der ersten 100 natürlichen Zahlen zu berechnen:[ 65 ](Das beim Funktionsaufruf von range(n) zurückgegebene iterierbare Objekt durchläuft alle ganzen Zahlen von 0 bis einschließlich n–1. Daher muss im Beispiel 101 anstelle von 100 übergeben werden. )

>>> summe(*range(101))
5050

Beim Funktionsaufruf wird der Funktion jedes Element des iterierbaren Objekts, in diesem Fall also die Zahlen von 0 bis 100, als gesonderter Parameter übergeben. Das Entpacken einer Parameterliste funktioniert nicht nur im Zusammenhang mit einer Funktion, die beliebig viele Parameter erwartet, sondern kann auch mit der ursprünglichen Funktion summe, die die Summe von maximal vier Parametern bestimmt, verwendet werden:

>>> def summe(a, b, c=0, d=0):
... return a + b + c + d

Beachten Sie dabei, dass das zu entpackende iterierbare Objekt auch maximal vier (und mindestens zwei) Elemente bereitstellt:

>>> t = (6, 3, 9, 12)
>>> summe(*t)
30
>>> summe(*[4, 6, 12, 7, 9])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: summe() takes from 2 to 4 positional arguments but 5 were given

Analog zum Entpacken eines Tupels zu einer Liste von Positionsparametern kann ein Dictionary zu einer Liste von Schlüsselwortparametern entpackt werden. Der Unterschied in der Notation besteht darin, dass zum Entpacken eines Dictionarys zwei Sternchen vorangestellt werden müssen:

>>> d = {"a" : 7, "b" : 3, "c" : 4}
>>> summe(**d)
14

Es ist noch zu erwähnen, dass die Techniken zum Entpacken von Parameterlisten miteinander kombiniert werden können, wie folgendes Beispiel zeigt:

>>> summe(1, *(2,3), **{"d" : 4})
10

Seit Python 3.5 ist es möglich, mehrere Sequenzen oder Dictionarys im selben Funktionsaufruf zu entpacken:

>>> summe(*(1,2), *(3,4))
10
>>> summe(*(1,2), **{"c" : 3}, **{"d" : 4})
10

Dabei dürfen Schlüsselwortargumente nicht mehrfach übergeben werden.

Zusätzlich gibt es seit Python 3.5 die Möglichkeit, auch beim Erzeugen von sequenziellen Datentypen, Mengen und Dictionarys auf Packing bzw. Unpacking zurückzugreifen:

>>> A = [1,2,3]
>>> B = [3,4,5]
>>> [1, *A, *B]
[1, 1, 2, 3, 3, 4, 5]
>>> {1, *A, *B}
{1, 2, 3, 4, 5}
>>> (1, *A, *B)
(1, 1, 2, 3, 3, 4, 5)
>>> {"a": 10, **{"b": 11, "c": 12}, "d": 13}
{'a': 10, 'b': 11, 'c': 12, 'd': 13}
>>> {"a": 10, **{"b": 11, "c": 12}, "d": 13, **{"e": 14}}
{'a': 10, 'b': 11, 'c': 12, 'd': 13, 'e': 14}

Wird bei einem Dictionary derselbe Schlüssel mehrfach übergeben, zählt das letzte Schlüssel-Wert-Paar:

>>> {"a": 10, **{"a": 11, "b": 12}, "a": 13, **{"b": 14}}
{'a': 13, 'b': 14}
[»]  Hinweis

Generell ist Vorsicht geboten, wenn Unpacking für ungeordnete Datentypen verwendet wird. Im folgenden Beispiel hängt die Reihenfolge der Elemente 1, 2, 3, 4, 5 davon ab, in welcher Reihenfolge über die Menge {3,4,1,2,5} iteriert wird:

>>> [0, *{3, 4, 1, 2, 5}]
[0, 1, 2, 3, 4, 5]

Da diese Reihenfolge ein Implementierungsdetail ist, kann sie sich zwischen verschiedenen Python-Versionen unterscheiden.

 
Zum Seitenanfang

19.3.6    Seiteneffekte Zur vorigen ÜberschriftZur nächsten Überschrift

Bisher haben wir diese Thematik geschickt umschifft, doch Sie sollten immer im Hinterkopf behalten, dass sogenannte Seiteneffekte (engl. side effects) immer dann auftreten können, wenn eine Instanz eines mutablen Datentyps, also zum Beispiel einer Liste oder eines Dictionarys, als Funktionsparameter übergeben wird.

In Python werden bei einem Funktionsaufruf keine Kopien der als Parameter übergebenen Instanzen erzeugt, sondern es wird funktionsintern mit Referenzen auf die Argumente gearbeitet.[ 66 ](Diese Methode der Parameterübergabe wird Call by Reference genannt. Demgegenüber steht das Prinzip Call by Value, bei dem funktionsintern auf Kopien der Argumente gearbeitet wird. Letztere Variante ist frei von Seiteneffekten, aber aufgrund des Kopierens langsamer. ) Betrachten Sie dazu folgendes Beispiel:

>>> def f(a, b):
... print(id(a))
... print(id(b))
...
>>> p = 1
>>> q = [1,2,3]
>>> id(p)
134537016
>>> id(q)
134537004
>>> f(p, q)
134537016
134537004

Im interaktiven Modus definieren wir zuerst eine Funktion f, die zwei Parameter a und b erwartet und deren jeweilige Identität ausgibt. Anschließend werden zwei Referenzen p und q angelegt, die eine ganze Zahl bzw. eine Liste referenzieren. Dann lassen wir uns die Identitäten der beiden Referenzen ausgeben und rufen die angelegte Funktion f auf. Sie sehen, dass die ausgegebenen Identitäten gleich sind. Es handelt sich also sowohl bei p und q als auch bei a und b im Funktionskörper um Referenzen auf dieselben Instanzen. Dabei macht es zunächst einmal keinen Unterschied, ob die referenzierten Objekte Instanzen eines veränderlichen oder unveränderlichen Datentyps sind.

Trotzdem ist die Verwendung eines unveränderlichen Datentyps grundsätzlich frei von Seiteneffekten, da dieser bei Veränderung automatisch kopiert wird und alte Referenzen davon nicht berührt werden. Sollten wir also beispielsweise a im Funktionskörper um eins erhöhen, werden nachher a und p verschiedene Instanzen referenzieren. Dies führt dazu, dass bei der Verwendung unveränderlicher Datentypen in Funktionsschnittstellen keine Seiteneffekte auftreten können.[ 67 ](Beachten Sie, dass dies nicht für unveränderliche Instanzen gilt, die veränderliche Instanzen enthalten. So können bei der Parameterübergabe eines Tupels, das eine Liste enthält, durchaus Seiteneffekte auftreten. )

Diese Sicherheit können uns veränderliche Datentypen, etwa Listen oder Dictionarys, nicht geben. Dazu folgendes Beispiel:

>>> def f(liste):
... liste[0] = 42
... liste += [5,6,7,8,9]
>>> zahlen = [1,2,3,4]
>>> f(zahlen)
>>> zahlen
[42, 2, 3, 4, 5, 6, 7, 8, 9]

Zunächst wird eine Funktion definiert, die eine Liste als Parameter erwartet und diese im Funktionskörper verändert. Daraufhin wird eine Liste angelegt, die der Funktion als Parameter übergeben und schlussendlich ausgegeben wird. Die Ausgabe zeigt, dass sich die Änderungen an der Liste nicht allein auf den Kontext der Funktion beschränken, sondern sich auch im Hauptprogramm auswirken. Dieses Phänomen wird Seiteneffekt genannt. Wenn eine Funktion nicht nur lesend auf eine Instanz eines veränderlichen Datentyps zugreifen muss und Seiteneffekte nicht ausdrücklich erwünscht sind, sollten Sie innerhalb der Funktion oder bei der Parameterübergabe eine Kopie der Instanz erzeugen. Das kann in Bezug auf das oben genannte Beispiel so aussehen:[ 68 ](Sie erinnern sich, dass beim Slicen einer Liste stets eine Kopie derselben erzeugt wird. Im Beispiel wurde das Slicing ohne Angabe von Start- und Endindex verwendet, um eine vollständige Kopie der Liste zu erzeugen. )

>>> zahlen = [1,2,3,4] 
>>> f(zahlen[:])
>>> zahlen
[1, 2, 3, 4]

Neben den bisher besprochenen Referenzparametern gibt es eine weitere, seltenere Form von Seiteneffekten, die auftritt, wenn ein veränderlicher Datentyp als Default-Wert eines Parameters verwendet wird:

>>> def f(a=[1,2,3]):
... a += [4,5]
... print(a)
...
>>> f()
[1, 2, 3, 4, 5]
>>> f()
[1, 2, 3, 4, 5, 4, 5]
>>> f()
[1, 2, 3, 4, 5, 4, 5, 4, 5]
>>> f()
[1, 2, 3, 4, 5, 4, 5, 4, 5, 4, 5]

Wir definieren im interaktiven Modus eine Funktion, die einen einzigen Parameter erwartet, der mit einer Liste vorbelegt ist. Im Funktionskörper wird diese Liste um zwei Elemente vergrößert und ausgegeben. Nach mehrmaligem Aufrufen der Funktion ist zu erkennen, dass es sich bei dem Default-Wert augenscheinlich immer um dieselbe Instanz gehandelt hat und nicht bei jedem Aufruf eine neue Liste mit dem Wert [1, 2, 3] erzeugt wurde.

Das liegt daran, dass eine Instanz, die als Default-Wert genutzt wird, nur einmalig und nicht bei jedem Funktionsaufruf neu erzeugt wird. Grundsätzlich sollten Sie also darauf verzichten, Instanzen veränderlicher Datentypen als Default-Werte zu verwenden. Schreiben Sie Ihre Funktionen stattdessen folgendermaßen:

>>> def f(a=None):
... if a is None:
... a = [1,2,3]

Selbstverständlich können Sie anstelle von None eine Instanz eines beliebigen anderen immutablen Datentyps verwenden, ohne dass Seiteneffekte auftreten.

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Python 3 Python 3
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Einstieg in Python
Einstieg in Python


Zum Rheinwerk-Shop: Python. Der Grundkurs
Python. Der Grundkurs


Zum Rheinwerk-Shop: Algorithmen mit Python
Algorithmen mit Python


Zum Rheinwerk-Shop: Objektorientierte Programmierung
Objektorientierte Programmierung


Zum Rheinwerk-Shop: Raspberry Pi. Das umfassende Handbuch
Raspberry Pi. Das umfassende Handbuch


Zum Rheinwerk-Shop: Roboter-Autos mit dem Raspberry Pi
Roboter-Autos mit dem Raspberry Pi


Zum Rheinwerk-Shop: Neuronale Netze programmieren mit Python
Neuronale Netze programmieren mit Python


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2020
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern