Argumente sind durch Abtretung übergeben . Dahinter stehen zwei Überlegungen:
- der übergebene Parameter ist eigentlich ein Referenz zu einem Objekt (aber die Referenz wird als Wert übergeben)
- einige Datentypen sind veränderbar, andere nicht
Donc :
-
Wenn Sie eine änderbar Objekt in eine Methode einbinden, erhält die Methode einen Verweis auf dasselbe Objekt und Sie können es nach Herzenslust verändern, aber wenn Sie den Verweis in der Methode neu binden, weiß der äußere Bereich nichts davon, und nachdem Sie fertig sind, zeigt der äußere Verweis immer noch auf das ursprüngliche Objekt.
-
Wenn Sie eine unveränderlich Objekt an eine Methode übergeben, können Sie die äußere Referenz immer noch nicht neu binden, und Sie können das Objekt nicht einmal ändern.
Um es noch deutlicher zu machen, hier einige Beispiele.
Liste - ein veränderlicher Typ
Versuchen wir, die Liste zu ändern, die an eine Methode übergeben wurde:
def try_to_change_list_contents(the_list):
print('got', the_list)
the_list.append('four')
print('changed to', the_list)
outer_list = ['one', 'two', 'three']
print('before, outer_list =', outer_list)
try_to_change_list_contents(outer_list)
print('after, outer_list =', outer_list)
Ausgabe:
before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']
Da der übergebene Parameter ein Verweis auf outer_list
und nicht eine Kopie davon ist, können wir die Methoden der mutierenden Liste verwenden, um sie zu ändern und die Änderungen im äußeren Bereich wiederzugeben.
Nun wollen wir sehen, was passiert, wenn wir versuchen, den als Parameter übergebenen Verweis zu ändern:
def try_to_change_list_reference(the_list):
print('got', the_list)
the_list = ['and', 'we', 'can', 'not', 'lie']
print('set to', the_list)
outer_list = ['we', 'like', 'proper', 'English']
print('before, outer_list =', outer_list)
try_to_change_list_reference(outer_list)
print('after, outer_list =', outer_list)
Ausgabe:
before, outer_list = ['we', 'like', 'proper', 'English']
got ['we', 'like', 'proper', 'English']
set to ['and', 'we', 'can', 'not', 'lie']
after, outer_list = ['we', 'like', 'proper', 'English']
Da die the_list
Parameter als Wert übergeben wurde, hatte die Zuweisung einer neuen Liste keine für den Code außerhalb der Methode sichtbaren Auswirkungen. Die the_list
war eine Kopie des outer_list
Referenz, und wir hatten the_list
auf eine neue Liste verweisen, aber es gab keine Möglichkeit zu ändern, wo outer_list
spitz.
String - ein unveränderlicher Typ
Sie ist unveränderlich, wir können also nichts tun, um den Inhalt der Zeichenkette zu ändern
Versuchen wir nun, die Referenz zu ändern
def try_to_change_string_reference(the_string):
print('got', the_string)
the_string = 'In a kingdom by the sea'
print('set to', the_string)
outer_string = 'It was many and many a year ago'
print('before, outer_string =', outer_string)
try_to_change_string_reference(outer_string)
print('after, outer_string =', outer_string)
Ausgabe:
before, outer_string = It was many and many a year ago
got It was many and many a year ago
set to In a kingdom by the sea
after, outer_string = It was many and many a year ago
Auch hier gilt, dass die the_string
Parameter als Wert übergeben wurde, hatte die Zuweisung einer neuen Zeichenkette keinen für den Code außerhalb der Methode sichtbaren Effekt. Die the_string
war eine Kopie des outer_string
Referenz, und wir hatten the_string
auf eine neue Zeichenkette verweisen, aber es gab keine Möglichkeit zu ändern, wo outer_string
spitz.
Ich hoffe, das klärt die Sache ein wenig auf.
EDITAR: Es wurde festgestellt, dass dies keine Antwort auf die Frage gibt, die @David ursprünglich gestellt hat: "Kann ich etwas tun, um die Variable per Referenz zu übergeben?". Lassen Sie uns daran arbeiten.
Wie können wir das umgehen?
Wie die Antwort von @Andrea zeigt, können Sie den neuen Wert zurückgeben. Dies ändert nichts an der Art und Weise, wie die Dinge übergeben werden, ermöglicht es Ihnen aber, die gewünschten Informationen zurückzubekommen:
def return_a_whole_new_string(the_string):
new_string = something_to_do_with_the_old_string(the_string)
return new_string
# then you could call it like
my_string = return_a_whole_new_string(my_string)
Wenn Sie die Verwendung eines Rückgabewerts wirklich vermeiden wollten, könnten Sie eine Klasse erstellen, die Ihren Wert aufnimmt und ihn an die Funktion weitergibt, oder eine vorhandene Klasse, z. B. eine Liste, verwenden:
def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change):
new_string = something_to_do_with_the_old_string(stuff_to_change[0])
stuff_to_change[0] = new_string
# then you could call it like
wrapper = [my_string]
use_a_wrapper_to_simulate_pass_by_reference(wrapper)
do_something_with(wrapper[0])
Dies scheint jedoch etwas umständlich zu sein.
32 Stimmen
Eine kurze Erklärung/Klarstellung finden Sie in der ersten Antwort auf diese Stackoverflow-Frage . Da Zeichenketten unveränderlich sind, werden sie nicht geändert und es wird eine neue Variable erstellt, so dass die "äußere" Variable immer noch denselben Wert hat.
11 Stimmen
Der Code in BlairConrads Antwort ist gut, aber die Erklärung von DavidCournapeau und DarenThomas ist richtig.
79 Stimmen
Bevor Sie die ausgewählte Antwort lesen, sollten Sie diesen kurzen Text lesen Andere Sprachen haben "Variablen", Python hat "Namen". . Denken Sie an "Namen" und "Objekte" anstelle von "Variablen" und "Referenzen" und Sie sollten viele ähnliche Probleme vermeiden.
2 Stimmen
Eine andere Möglichkeit besteht darin, eine Wrapper-"Referenz" wie folgt zu erstellen: ref = type('', (), {'n':1}) stackoverflow.com/a/1123054/409638
1 Stimmen
Für globale Namen kann die Referenzübergabe simuliert werden, indem der Name als String übergeben und globals() verwendet wird.
def change(s): globals()[s] = 'changed'
gefolgt vona = 'orig'; change('a'); print(a)
druckt'changed'
.0 Stimmen
Einige unveränderliche Typen: {int, float, long, complex, str, bytes, tuple, frozen set} Einige veränderliche Typen: {byte array, list, set, dict}
1 Stimmen
Python hat Variablen. Es gibt überhaupt kein konzeptionelles Problem mit diesem Begriff, und er ist allgemein gebräuchlich.
0 Stimmen
jeff Knupps Blog y stupidpythonideas sind einige gute Erklärungen dafür.
0 Stimmen
Geben Sie mir für den Datenrahmen mit dem Namen "bob" (aus einer String-Variablen, und das ist der knifflige Teil) dessen aktuellen Inhalt. Das sollte einfach sein. Leider bekomme ich es nicht.
4 Stimmen
Funktionierender Link: Andere Sprachen haben "Variablen", Python hat "Namen".
13 Stimmen
Neuer offizieller Weg des Iqc's Link: david.goodger.org/projects/pycon/2007/idiomatic/
0 Stimmen
Ich komme von C# und versuche, die Frage besser zu verstehen. In Python ist alles ein Objekt und Objekte können veränderbar oder unveränderbar sein. Der Code hier verwendet "string", das ein unveränderliches Objekt ist, und der Versuch, es innerhalb des Funktionsumfangs zu ändern, wird den Wert des Aufrufers nicht ändern (verhält sich wie Pass-by-Value) & wenn der Code ein veränderbares benutzerdefiniertes Klassenobjekt verwendet - eine Änderung innerhalb des Funktionsumfangs wird den Wert des Aufrufers ändern (verhält sich wie Pass-by-Ref). In C# sehen Sie genau das gleiche Ergebnis (aber die Art, wie es erreicht wird, ist pass-by-value/ref). Ist der Nettoeffekt also nicht derselbe? Ist die Frage also nicht überflüssig?
0 Stimmen
@PeterR weil OOP > 70er Jahre Programmierung ohne Klassen und Objekte. Es ist einfach einfacher, Programme zu schreiben und zu verstehen, wenn sie objektorientiert sind. Ich denke, dass alles im Universum als Objekt dargestellt werden kann, sogar das, was in realen Programmierkonzepten nicht vorhanden ist.
1 Stimmen
@Naren nein, es verhält sich nicht wie ein Aufruf per Verweis oder ein Aufruf per Wert . Die Zuweisung eines Parameters, unabhängig vom verwendeten Typ, wird jamais im Aufrufer zu sehen sein, daher handelt es sich nicht um einen Verweisaufruf. Ähnlich verhält es sich bei Objekten werden nicht kopiert Wenn sie an eine Funktion übergeben werden, wirken sich Mutator-Methoden unabhängig vom verwendeten Typ überall dort auf diese Objekte aus, wo sie referenziert werden.