Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
1 Einleitung
2 Überblick über Python
3 Die Arbeit mit Python
4 Der interaktive Modus
5 Grundlegendes zu Python-Programmen
6 Kontrollstrukturen
7 Das Laufzeitmodell
8 Basisdatentypen
9 Benutzerinteraktion und Dateizugriff
10 Funktionen
11 Modularisierung
12 Objektorientierung
13 Weitere Spracheigenschaften
14 Mathematik
15 Strings
16 Datum und Zeit
17 Schnittstelle zum Betriebssystem
18 Parallele Programmierung
19 Datenspeicherung
20 Netzwerkkommunikation
21 Debugging
22 Distribution von Python-Projekten
23 Optimierung
24 Grafische Benutzeroberflächen
25 Python als serverseitige Programmiersprache im WWW mit Django
26 Anbindung an andere Programmiersprachen
27 Insiderwissen
28 Zukunft von Python
A Anhang
Stichwort

Download:
- ZIP, ca. 4,8 MB
Buch bestellen
Ihre Meinung?

Spacer
 <<   zurück
Python von Peter Kaiser, Johannes Ernesti
Das umfassende Handbuch - Aktuell zu Python 2.5
Buch: Python

Python
gebunden, mit CD
819 S., 39,90 Euro
Galileo Computing
ISBN 978-3-8362-1110-9
Pfeil 10 Funktionen
  Pfeil 10.1 Schreiben einer Funktion
  Pfeil 10.2 Funktionsparameter
    Pfeil 10.2.1 Optionale Parameter
    Pfeil 10.2.2 Schlüsselwortparameter
    Pfeil 10.2.3 Beliebige Anzahl von Parametern
    Pfeil 10.2.4 Seiteneffekte
  Pfeil 10.3 Zugriff auf globale Variablen
  Pfeil 10.4 Lokale Funktionen
  Pfeil 10.5 Anonyme Funktionen
  Pfeil 10.6 Rekursion
  Pfeil 10.7 Vordefinierte Funktionen


Galileo Computing - Zum Seitenanfang

10.2 Funktionsparameter  Zur nächsten ÜberschriftZur vorigen Ü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 sollen drei Techniken eingeführt werden, die die Verwendung von Funktionsparametern bequemer oder eleganter machen. Alle drei Techniken sind mehr oder weniger speziell und somit nicht für alle Einsatzgebiete von Funktionen geeignet.


Galileo Computing - Zum Seitenanfang

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

Zu Beginn dieses Kapitels wurde die Verwendung einer Funktion anhand der Built-in Function range erklärt. Erinnern Sie sich noch daran, als range im Zusammenhang mit der for-Schleife eingeführt wurde? Wenn ja, dann wissen Sie sicherlich noch, dass unter anderem der letzte der drei Parameter optional war. Das bedeutet zunächst einmal, dass dieser Parameter beim Funktionsaufruf weggelassen werden kann. Ein optionaler Parameter muss funktionsintern mit einem Wert vorbelegt sein, üblicherweise einen 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) 
[2, 3, 4, 5, 6, 7, 8, 9] 
>>> range(2, 10) 
[2, 3, 4, 5, 6, 7, 8, 9]

Dies ist ein interessantes Sprachmerkmal von Python, 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 völlig überflüssigen Parameter anzugeben. Deswegen sind vordefinierte Parameterwerte oft eine sinnvolle Ergänzung der eigenen Funktionsschnittstelle.

Um einen Funktionsparameter mit einem Defaultwert 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 durchführen zu können, müssen mindestens zwei Parameter übergeben worden sein. Die anderen beiden werden mit 0 vorbelegt. Sollten sie beim Funktionsaufruf nicht explizit angegeben werden, so fließen sie in die Addition nicht ein. Die Funktion könnte folgendermaßen aufgerufen werden:

summe(1, 2) 
summe(1, 2, 3) 
summe(1, 2, 3, 4)

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 zuzuordnen sind.


Galileo Computing - Zum Seitenanfang

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

Neben den bislang verwendeten sogenannten positional arguments gibt es in Python eine weitere Möglichkeit, Parameter zu übergeben. Solche Parameter werden keyword arguments genannt. Es handelt sich dabei lediglich um eine weitere 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)

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)

Beachten Sie außerdem, dass nur solche Parameter als keyword arguments übergeben werden dürfen, die im selben Funktionsaufruf nicht bereits als positional argument übergeben wurden.

Zum Schluss möchten wir noch anmerken, dass optionale Parameter auch unter Verwendung von keyword arguments wie erwartet funktionieren.


Galileo Computing - Zum Seitenanfang

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

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) 
funktion(1, 2, "Hallo Welt", 42, [1,2,3,4])

Die Ausgabe der Funktion im Falle des ersten Aufrufs wäre:

Feste Parameter: 1 2 
Weitere Parameter: ()

Der Parameter weitere referenziert also ein leeres Tupel. Im Falle des zweiten Aufrufs sähe die Ausgabe folgendermaßen aus:

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

Der Parameter weitere referenziert nun ein Tupel, in dem alle über a und b hinausgehenden Instanzen in der Reihenfolge enthalten sind, wie sie übergeben wurden.

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, sowie darin, dass er später kein Tupel, sondern ein Dictionary referenziert. 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) 
funktion(1, 2, johannes="ernesti", peter="kaiser")

Die Ausgabe nach dem ersten Funktionsaufruf sähe folgendermaßen aus:

Feste Parameter: 1 2 
Weitere Parameter: {}

Der Parameter weitere referenziert also ein leeres Dictionary. Nach dem zweiten Aufruf sähe die Ausgabe so aus:

Feste Parameter: 1 2 
Weitere Parameter: {'johannes': 'ernesti', 'peter': 'kaiser'}

Beide Techniken können zusammen verwendet werden, wie folgende Funktionsdefinition zeigt:

def funktion(*positional, **keyword): 
    print positional 
    print keyword

Der Funktionsaufruf

funktion(1, 2, 3, 4, hallo="welt", key="word")

gibt diese Werte aus:

(1, 2, 3, 4) 
{'hallo': 'welt', 'key': 'word'}

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

Entpacken einer Parameterliste

Wenn eine Funktion beliebige Parameter erwartet, kommen diese funktionsintern gesammelt entweder in Form eines Tupels (positional arguments) oder eines Dictionarys (keyword arguments) an. Gelegentlich möchte man die in diesem Tupel bzw. Dictionary enthaltenen Parameter an eine andere Funktion weiterreichen. Dabei soll aber jedes Element des Tupels bzw. jedes Schlüssel/Wert-Paar des Dictionarys beim Aufruf der zweiten Funktion als eigenständiger Parameter übergeben werden. Dieser Vorgang wird Entpacken eines Tupels oder eines Dictionarys genannt.

Das Entpacken eines Tupels soll an einem Beispiel verdeutlicht werden. Dazu definieren wir zwei Funktionen, f1 und f2, wobei f1 über eine feste Schnittstelle verfügt, während f2 beliebig viele positional arguments akzeptiert. Die Funktion f2 soll die ihr übergebenen Parameter, auf die sie in Form eines Tupels zugreifen kann, entpacken und an die Funktion f1 weiterreichen.

def f1(a, b, c, d): 
    print "Parameter:", a, b, c, d
def f2(*prm): f1(*prm)

Zur Funktion f1 muss nicht viel gesagt werden: Sie erwartet vier Parameter und gibt diese auf dem Bildschirm aus. Viel interessanter ist die Funktion f2, die eine beliebige Anzahl Positionsparameter erwartet und diese im Funktionskörper an die Funktion f1 weiterreichen soll. Das Tupel prm, das die der Funktion f2 übergebenen Parameter enthält, kann im Funktionsaufruf von f1 durch ein vorangestelltes Sternchen (*) entpackt werden. Wenn das Tupel vier Elemente enthält, kommen diese in Form der Parameter a, b, c und d bei f1 an. Sollte das Tupel weniger oder mehr Elemente enthalten, verursacht dies einen Fehler. So gibt f1 bei einem Funktionsaufruf von

f2(1, 2, 3, 4)

den Text

Parameter: 1 2 3 4

auf dem Bildschirm aus.

Analog dazu kann ein Dictionary mit zwei vorangestellten Sternchen entpackt werden:

def f1(a, b, c, d): 
    print "Parameter:", a, b, c, d
def f2(**prm): f1(**prm)

In diesem Fall verursacht der Funktionsaufruf

f2(a=5, b=6, c=7, d=8)

die erwartete Bildschirmausgabe:

Parameter: 5 6 7 8

Beachten Sie allgemein, dass die hier vorgestellte Syntax nur innerhalb eines Funktionsaufrufs verwendet werden darf und außerhalb dessen zu einem Fehler führt.


Galileo Computing - Zum Seitenanfang

10.2.4 Seiteneffekte  topZur vorigen Überschrift

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

Um dies verstehen zu können, müssen wir zunächst allgemein darüber sprechen, auf welchen Wegen Funktionsparameter übergeben werden. In der Programmierung unterscheidet man dabei grob zwei Arten:

Bei einem call-by-value wird funktionsintern mit Kopien der als Parameter übergebenen Instanzen gearbeitet. Das hat den Vorteil, dass eine Funktion keine ungewollten Änderungen im Hauptprogramm bewirken kann, erzeugt jedoch unter Umständen einen erheblichen Overhead, da auch größere Instanzen wie Listen oder Dictionarys bei jedem Funktionsaufruf kopiert werden müssten.

Das gegensätzliche Prinzip wird call-by-reference genannt und bedeutet, dass funktionsintern mit Referenzen auf die im Hauptprogramm befindlichen Instanzen gearbeitet wird. Der Vorteil dieser Methode liegt auf der Hand: Es müssen keine Instanzen kopiert werden, und ein Funktionsaufruf wird dementsprechend performant. Der größte Nachteil der Referenzparameter ist, dass innerhalb einer Funktion eine übergebene Instanz so verändert werden kann, dass sich dies auch im Hauptprogramm auswirkt. Solche Änderungen sind vom Programmierer meist nicht erwünscht und werden als Seiteneffekte bezeichnet.

In Python werden Funktionsparameter grundsätzlich »by reference« übergeben. Betrachten Sie dazu folgendes Beispiel, das sich zunächst auf unveränderliche Datentypen wie int oder float beschränkt:

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

Im interaktiven Modus definieren wir zuerst eine Funktion, die zwei Parameter a und b erwartet und ihre jeweilige Identität ausgibt. Nachfolgend werden zwei Referenzen p und q angelegt, die je eine Instanz des Datentyps int 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.

Trotzdem ist die Verwendung eines immutable 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, so werden nachher a und p verschiedene Instanzen referenzieren. Dies ermöglicht es uns, mit unveränderlichen Parametern umzugehen, als wären sie »by value« übergeben worden.

Diese Sicherheit können uns mutable Datentypen nicht geben. Dazu folgendes Beispiel:

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

Zunächst wird eine Funktion definiert, die eine Liste als Parameter erwartet und diese im Funktionskörper verändert. Im Hauptprogramm wird eine Liste angelegt und ausgegeben. Danach wird die Funktion aufgerufen und die Liste erneut ausgegeben. Die Ausgabe des Beispiels sieht folgendermaßen aus:

[1, 2, 3, 4] 
[42, 2, 3, 4, 5, 6, 7, 8, 9]

Es ist zu erkennen, dass sich die Änderungen nicht allein auf den Kontext der Funktion beschränken, sondern sich auch im Hauptprogramm auswirken. 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 könnte in Bezug auf das obige Beispiel so aussehen: [Sie erinnern sich, dass beim Slicen einer Liste stets eine Kopie derselben erzeugt wird. Im Beispiel wurde das Slicing genutzt, um eine vollständige Kopie der Liste zu erzeugen, indem weder ein Start- noch ein Endindex angegeben wurde. ]

f(zahlen[:])

Neben den bisher besprochenen Referenzparametern existiert eine weitere, seltenere Form von Seiteneffekten, die auftritt, wenn ein veränderlicher Datentyp als Defaultwert 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 Defaultwert augenscheinlich immer um dieselbe Instanz gehandelt hat.

Das liegt daran, dass eine Instanz, die als Defaultwert genutzt wird, nur einmalig und nicht bei jedem Funktionsaufruf neu erzeugt wird. Grundsätzlich sollten Sie also darauf verzichten, Instanzen unveränderlicher Datentypen als Defaultwert 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 statt None eine Instanz eines beliebigen anderen immutable Datentypen verwenden, ohne dass Seiteneffekte auftreten.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.






 <<   zurück
  
  Zum Katalog
Zum Katalog: Python






Python
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Linux






 Linux


Zum Katalog: Ubuntu GNU/Linux






 Ubuntu GNU/Linux


Zum Katalog: Praxisbuch Web 2.0






 Praxisbuch Web 2.0


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Praxisbuch Objektorientierung






 Praxisbuch Objektorientierung


Zum Katalog: Einstieg in SQL






 Einstieg in SQL


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für Fachinformatiker


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2008
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.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de