Hallo,
ich versuche gerade zu durchblicken wann Python Variablen als Wert und wann als Referenz übergibt.
Wenn ich eine Funktion aufrufe, dann macht Python die Übergabe als Wert, egal von welchem Typ die Variable ist, richtig?
Erzeuge ich eine einfache Variable wie "a = 5" und mache danach b = a und danach a = 6, dann müsste b immer noch 5 sein. D.h. Python kopiert hier die Variable echt.
Mache ich jedoch eine Liste zb. "a = [1, 2, 3]" und dann ein b = a und danach dein a.append(5), dann ist b hinterher auch [1, 2, 3, 5]. D.h. bei Variablen die ein Objekt oder eine Liste enthalten macht der = Operator keine Kopie sondern nur eine Referenz, richtig?
Kann man letzters irgendwie umgehen? Ich müsste eine Liste echt kopieren und nicht nur eine neue Referenz erzeugen?
Gruß
nbkr
Variable = Variable? Mal Wert mal Referenz?
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Das geht auf mancherlei Weise:
Das id()-Builtin ist für sowas auch sehr praktisch.
Code: Alles auswählen
b = a[:]
import copy
b = copy.copy(a)
id(a)
id(b)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Wenn man in die Suche "Listen kopieren" eingibt landet man hier:
http://www.python-forum.de/topic-398.ht ... n+kopieren
http://www.python-forum.de/topic-398.ht ... n+kopieren
Doch das stimmt auch bei der Übergabe an eine Funktion. Python übergibt immer Referenzen. Und wenn Du ein Objekt innerhalb einer Funktion änderst, dann ist das auch immer ausserhalb sichtbar.nbkr hat geschrieben:Das stimmt aber nicht bei Übergabe einer Variable an eine Funktion. Sonst würde die Änderungen die die Funktion vornimmt ja gleich auf die Variable durchschlagen.
Du scheinst Dich durch so etwas hier verwirren zu lassen:
Code: Alles auswählen
a = 42
def test(val):
val = 23
test(a)
print a # -> 42
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hi nbkr!nbkr hat geschrieben:Das stimmt aber nicht bei Übergabe einer Variable an eine Funktion. Sonst würde die Änderungen die die Funktion vornimmt ja gleich auf die Variable durchschlagen.
Der Unterschied ist nicht ob es eine Referenz zu einem Objekt ist, oder nicht, sondern ob der Variabletype mutable (veränderbar) oder immutable (unveränderbar) ist.
Und, JA --> Python arbeitet immer mit Referenzen.
Bei Python sind gewisse Variabletypen veränderbar und gewisse nicht. Das ist genau definiert.
Nicht veränderbare Variabletypen können nur überschrieben, nicht verändert werden.
Nicht veränderbare Variabletypen sind:
- String
- Integer
- Long
- Tupel
Veränderbare Variabletypen sind:
- Liste
- Dictionary
Hier ein kleines Beispiel:
Wenn ich einer Variable einer Zahl zuweise, dann wird, falls diese Zahl noch nie verwendet wurde, dieser Zahl ein Speicherplatz zugewiesen und die Variable ist der Name zu diesem Speicherplatz.
Code: Alles auswählen
>>> a = 5
>>> id(a)
134540408
>>>
Code: Alles auswählen
>>> b = 5
>>> id(b)
134540408
>>>
Bei veränderbaren Datentypen verhält es sich komplett anders. Wird eine Variable einer Liste zugewiesen, dann wird immer eine neue Liste erstellt, einem Speicherplatz zugewiesen und die Variable auf den neuen Speicherplatz verwiesen. Somit ist die Basis veränderbarer Variablen, einfach nur ein Speicherplatz, der sich nicht mit anderen überschneiden kann. Reicht später der Speicherplatz nicht mehr aus, dann wird einfach zusätzlicher Speicherplatz angefordert. Das passiert transparent im Hintergrund und ist für den Programmierer nicht wichtig.
Code: Alles auswählen
>>> liste_1 = []
>>> id(liste_1)
-1216406356
>>> liste_2 = []
>>> id(liste_2)
-1216406068
>>>
Wie man im Beispiel sieht, wird der zweiten Liste eine neue Speicheradresse zugewiesen.
Wird einer neuen Variable eine bereits existierende, unveränderliche Variable zugewiesen, dann wird der neuen Variable einfach nur der unveränderliche Wert (oder dessen Speicherbereich) zugewiesen. Beide Variablen, die alte und die neue, hängen nicht zusammen, sondern stellen beide eine Referenz zu einem unveränderlichen Wert dar. Es gibt keinen Unterschied, ob ich beiden Variablen beim Erstellen den Wert oder eine Variable zugewiesen habe. Beide sind im Ergebnis gleich --> je eine Variable zu einem unveränderlichen Wert. Wird im Nachhinein der alten Variable ein neuer Wert zugewiesen, dann ändert sich zwar der Wert und der Speicherbereich der alten Variable, die neue Variable ändert sich aber nicht, da sie ja per Definition auf eine unveränderliche Variable verweist.
Code: Alles auswählen
>>> a = 5
>>> b = a
>>> id(a)
134540408
>>> id(b)
134540408
>>> a = 10
>>> a
10
>>> b
5
>>> id(a)
134540348
>>> id(b)
134540408
>>>
Code: Alles auswählen
>>> liste_1 = [10, 20]
>>> id(liste_1)
-1216406004
>>> liste_2 = liste_1
>>> id(liste_2)
-1216406004
>>> liste_1 = [30, 40]
>>> id(liste_1)
-1216405940
>>> id(liste_2)
-1216406004
>>> liste_1
[30, 40]
>>> liste_2
[10, 20]
Im nächsten Beispiel, wird zuerst der Variable "liste_2" der gleiche Speicherbplatz wie der Variable "liste_1" zugewiesen. Danach wird aber nur der Inhalt des Speicherbereichs verändert. Beide Variablen zeigen noch auf den selben Speicherbereich. Deshalb zeigen beide Variablen auch auf den selben Wert.
Code: Alles auswählen
>>> liste_1 = [10, 20]
>>> liste_2 = liste_1
>>> id(liste_1)
-1216406100
>>> id(liste_2)
-1216406100
>>> liste_1[0] = 30
>>> liste_1
[30, 20]
>>> liste_2
[30, 20]
>>> id(liste_1)
-1216406100
>>> id(liste_2)
-1216406100
>>>
Auch wenn mehrere Variablen auf einen unveränderbaren Datentyp zeigen, ein Ändern einer dieser Variablen, weist dieser einen neuen Speicherbereich zu. Die anderen Variablen bleiben davon unbetroffen.
Auch wenn mehrere Variablen auf einen veränderbaren Datentyp zeigen, ein einzelnes Zuweisen eines neuen Speicherbereichs, einer dieser Variablen, wirkt sich nicht auf die anderen Variablen aus. Wird allerdings der Inhalt des Speicherbereichs verändert, dann wirkt sich das auf alle Variablen aus, die auf diesen Speicherbereich zeigen.
mfg
Gerold

PS: Weitere Lektüre: http://www.python-forum.de/topic-5903.html
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Danke für die mehr als ausführlich Antwort ;-)
Dann wird auch klar warum das Anhängen von Daten an die eine Liste dazu führt das die bei der "Kopie" (auch wenns keine ist) auch auftauchen.
Das ganze (im)mutable Konzept führt letzten Endes auch dazu, das Python keine explizite Übergabe per Referenz oder per Wert hat. Das ist quasi Built-In.
Übergibt man eine immutable Variable (eine einfache Zahl) und verändert deren Wert innerhalb der Funktion wird ein neuer Speicherbereich für die Zahl generiert. D.h. der Wert der Variablen ändert sich nur innerhalb der Funktion. Dies würde dem klassischen "Call by value" entsprechen.
Übergibt man eine mutable Variable (eine Liste) und hängt innerhalb der Funkktion einen Wert an, so passiert dies auch außerhalb (weil der Speicherbereich bei mutable Typen nicht geändert wird). Das würde also dem klassischen "Call by reference" entsprechen.
Um jetzt eine mutable Variable innerhalb einer Funktion ändern zu können ohne das es ein Problem mit dem Variablennamen außerhalb gibt, muss man innerhalb der Funktion also folgendes machen:
Somit hätte man innerhalb der Funktion eine mutable Variable mylist die mit der Variablen mylist außerhalb der Funktion nichts mehr zu tun hat.
Bei imutable Variablen muss man deren neuen Wert wieder zurückgeben wenn man diesen außerhalb der Funktion wieder benötigt. Da Python mehr als einen Rückgabewert für eine Funktion kennt kann damit praktisch das Call by Reference andere Sprachen nachempfinden.
Hach, schön wenn man was lernt ;-)
Danke an alle!
Dann wird auch klar warum das Anhängen von Daten an die eine Liste dazu führt das die bei der "Kopie" (auch wenns keine ist) auch auftauchen.
Das ganze (im)mutable Konzept führt letzten Endes auch dazu, das Python keine explizite Übergabe per Referenz oder per Wert hat. Das ist quasi Built-In.
Übergibt man eine immutable Variable (eine einfache Zahl) und verändert deren Wert innerhalb der Funktion wird ein neuer Speicherbereich für die Zahl generiert. D.h. der Wert der Variablen ändert sich nur innerhalb der Funktion. Dies würde dem klassischen "Call by value" entsprechen.
Übergibt man eine mutable Variable (eine Liste) und hängt innerhalb der Funkktion einen Wert an, so passiert dies auch außerhalb (weil der Speicherbereich bei mutable Typen nicht geändert wird). Das würde also dem klassischen "Call by reference" entsprechen.
Um jetzt eine mutable Variable innerhalb einer Funktion ändern zu können ohne das es ein Problem mit dem Variablennamen außerhalb gibt, muss man innerhalb der Funktion also folgendes machen:
Code: Alles auswählen
def whatever(mylist):
mylist = mylist[:]
Bei imutable Variablen muss man deren neuen Wert wieder zurückgeben wenn man diesen außerhalb der Funktion wieder benötigt. Da Python mehr als einen Rückgabewert für eine Funktion kennt kann damit praktisch das Call by Reference andere Sprachen nachempfinden.
Hach, schön wenn man was lernt ;-)
Danke an alle!
An dieser Stelle fangen dann die "religiösen" Kriege an. Ist das nun "call by reference" oder "call by value" wobei die Werte grundsätzlich Referenzen sind? Ich bin eigentlich für letzteres, weil es IMHO keinen Sinn macht von "call by reference" zu sprechen, wenn man als Programmierer gar nicht an die Referenz selbst heran kommt, wie z.B. in C, sondern grundsätzlich immer nur an den Wert auf den verwiesen wird.nbkr hat geschrieben:Übergibt man eine mutable Variable (eine Liste) und hängt innerhalb der Funkktion einen Wert an, so passiert dies auch außerhalb (weil der Speicherbereich bei mutable Typen nicht geändert wird). Das würde also dem klassischen "Call by reference" entsprechen.
Da gab's schon ellenlange Diskussionen in der englischsprachigen Python-Newsgroup. Unter anderem auch mit dem Vorschlag das "call by value/reference" beides auf Python nicht so richtig passt und man vielleicht lieber von "call by object" sprechen sollte
Doch, auch die Kopie enthält noch die selben Objekte und wenn die mutable sind, dann "sieht" man Änderungen natürlich auch ausserhalb der Funktion.Um jetzt eine mutable Variable innerhalb einer Funktion ändern zu können ohne das es ein Problem mit dem Variablennamen außerhalb gibt, muss man innerhalb der Funktion also folgendes machen:Somit hätte man innerhalb der Funktion eine mutable Variable mylist die mit der Variablen mylist außerhalb der Funktion nichts mehr zu tun hat.Code: Alles auswählen
def whatever(mylist): mylist = mylist[:]