Parameterübergabe
Wertübergabe oder Referenzübergabe
In den Programmiersprachen unterscheidet man im Wesentlichen zwischen zwei Formen der Parameterübergabe:
- Wertübergabe (call by value)
Bei der Wertübergabe stellt beim Aufruf einer Funktion jedes Argument einen Wert dar, der ausgewertet wird. Dieser Wert wird dann an den entsprechenden formalen Parameter übergeben, d.h. der Wert des i-ten Ausdrucks (Parameter) wird beim Aufruf dem i-ten Parameter zugewiesen. Die Ausdrücke können aus Literale , Variablen oder beliebigen Ausdrücke (wie z.B. "a + b + 7" bestehen. Werte von übergebenen Parametern können nicht verändert werden! - Referenzübergabe(call by reference)
Bei der Referenzübergabe werden, wie der Name impliziert, Referenzen (Speicheradressen) übergeben, d.h. die Speicheradresse des jeweiligen tatsächlichen Parameters. Der formale Parameter wird also zu einem Zeiger auf die Speicheradresse des aufrufenden Parameters. Das bewirkt, dass alle Änderungen an diesem Parameter innerhalb der Funktion sich auch im aufrufenden Teil des Programmes auswirken. Das bedeutet aber auch, dass die tatsächlichen Parameter beim Aufruf nur Ausdrücke sein können, deren Adresse berechnet werden können, also Variablen.
und wie sieht es bei Python aus?
In vielen Büchern oder Einführungen in Python liest man, dass Python den einen oder den anderen Übergabemechanismus habe, also "call by reference" oder "call by value". Was ist nun richtig?
Die Erklärung liefert uns Humpty Dumpty:
"Wenn ich ein Wort verwende", erwiderte Humpty Dumpty ziemlich geringschätzig, "dann bedeutet es genau, was ich es bedeuten lasse, und nichts anderes."
"Die Frage ist doch", sagte Alice, "ob du den Worten einfach so viele verschiedene Bedeutungen geben kannst".
"Die Frage ist", sagte Humpty Dumpty, "wer die Macht hat - und das ist alles. [...]"
Lewis Carroll, Through the Looking-Glass (Alles hinter den Spiegeln)
Die Autoren "dehnen" die ursprünglichen Begriffe, so dass sie passen.
Python benutzt einen Mechanismus, den man als "Call-by-Object" (auch "Call by Object Reference" oder "Call by Sharing") bezeichnet.
Beim Aufruf einer Funktion werden bei Python nicht Zeiger auf Variablen
sondern Zeiger auf die zugrundeliegenden Objekte übergeben, insofern könnte
man von einer Art Referenzübergabe sprechen.Zur Erklärung betrachten wir das folgende Beispiel:
def ref_demo(x):
print "x=",x," id=",id(x)
x=42
print "x=",x," id=",id(x)
Ruft man diese Funktion auf (siehe weiter unten) und überprüft gleichzeitig mittels der
build-in-Funktion id() die Identität der Variable x, stellt man fest, dass das
globale x so lange dem lokalen x der Funktion entspricht, bis man x in der
Funktion einen anderen Wert zuweist.
So verhält sich Python zuerst wie "call
by reference", dann wie "call by value". Allerdings kann man beim Aufruf im
Gegensatz zu einem echten "call by reference" beliebige Ausdrücke, wie bei der
Wertübergabe übergeben.
>>> x=9 >>> ref_demo(x) x= 9 id= 29488104 x= 42 id= 29489304 >>> id(x) 29488104 >>>
Seiteneffekte
Von einem Funktionsaufruf erwartet man, dass die Funktion den korrekten Wert für die Argumente zurückliefert und sonst keine Effekte verursacht, z.B. Ändern von Speicherzuständen. Auch wenn manche Programmierer bewusst Seiteneffekte zur Lösung ihrer Probleme einsetzen, wird dies im Allgemeinen als schlechter Stil betrachtet.Schlimmer ist es jedoch, wenn Seiteneffekte auftreten, mit denen man nicht gerechnet hat, und dadurch Fehler verursacht werden. Dies kann auch in Python passieren. Dies kann dann geschehen, wenn Listen oder Dictionaries als Parameter übergeben werden.
Im folgenden Beispiel wird die Liste fib, die als aktueller Parameter an die Funktion s() übergeben wird, mit der Liste [47,11] verkettet.
>>> def s(liste): ... print id(liste) ... liste += [47,11] ... print id(liste) ... >>> fib = [0,1,1,2,3,5,8] >>> id(fib) 24746248 >>> s(fib) 24746248 24746248 >>> id(fib) 24746248 >>> fib [0, 1, 1, 2, 3, 5, 8, 47, 11]Man kann dies verhindern, wenn man statt einer Liste eine Kopie der Liste als Parameter übergibt. Mittels der Slicing Funktion kann man ganz leicht eine Kopie erzeugen. So wird in s(fib[:]) nicht die Liste fib sonder eine komplette Kopie übergeben. Der Aufruf verändert also nicht den Wert von fib, wie man im folgenden interaktiven Programmstück sehen kann:
>>> def s(liste): ... liste += [47,11] ... print liste ... >>> fib = [0,1,1,2,3,5,8] >>> s(fib[:]) [0, 1, 1, 2, 3, 5, 8, 47, 11] >>> fib [0, 1, 1, 2, 3, 5, 8]
Übergabe von Argumenten
Nicht nur Funktionen, sondern auch einem Python-Skript kann man Argumente übergeben. Ruft man ein Python-Skript aus einer Shell auf, werden die Argumten jeweils durch ein Leerzeichen voneinander getrennt hinter dem Skriptnamen aufgeführt. Im Python-Skript selber sind diese Argumente unter der Listenvaribale sys.argv abrufbar. Der Name des Skriptes (Dateiname) ist unter sys.argv[0] erreichbar.Das Skript (argumente.py) listet sämtliche mitgegebenen Argumente in der Standardausgabe auf:
# Modul sys wird importiert:
import sys
# Iteration über sämtliche Argumente:
for eachArg in sys.argv:
print eachArg
Beispiel eines Aufrufes, falls das Skript unter argumente.py gespeichert worden ist:
python argumente.py python kurs fuer anfaengerDieser Aufruf erzeugt folgende Ausgabe
argumente.py python kurs fuer anfaenger
Die Priesterinnen von Delphi hießen nach der Schlange Pythien.
This topic in English / Englische Version: