Während pass by reference nichts ist, was gut in Python passt und nur selten verwendet werden sollte, gibt es einige Umgehungsmöglichkeiten, die tatsächlich funktionieren können, um das Objekt zu erhalten, das aktuell einer lokalen Variable zugewiesen ist, oder sogar eine lokale Variable innerhalb einer aufgerufenen Funktion neu zuweisen.
Die Grundidee besteht darin, eine Funktion zu haben, die diesen Zugriff durchführen kann und die als Objekt an andere Funktionen übergeben oder in einer Klasse gespeichert werden kann.
Eine Möglichkeit ist die Verwendung von global
(für globale Variablen) oder nonlocal
(für lokale Variablen in einer Funktion) in einer Wrapper-Funktion.
def change(wrapper):
wrapper(7)
x = 5
def setter(val):
global x
x = val
print(x)
Die gleiche Idee gilt für das Lesen und del
eine Variable zu bestimmen.
Für das reine Lesen gibt es sogar eine kürzere Möglichkeit, indem man einfach lambda: x
die eine Callable zurückgibt, die bei ihrem Aufruf den aktuellen Wert von x zurückgibt. Das ist so ähnlich wie "call by name", das in früheren Sprachen verwendet wurde.
Die Übergabe von 3 Wrappern für den Zugriff auf eine Variable ist etwas umständlich, so dass diese in eine Klasse mit einem Proxy-Attribut verpackt werden können:
class ByRef:
def __init__(self, r, w, d):
self._read = r
self._write = w
self._delete = d
def set(self, val):
self._write(val)
def get(self):
return self._read()
def remove(self):
self._delete()
wrapped = property(get, set, remove)
# left as an exercise for the reader: define set, get, remove as local functions using global / nonlocal
r = ByRef(get, set, remove)
r.wrapped = 15
Pythons "Reflection"-Unterstützung macht es möglich, ein Objekt zu erhalten, das in der Lage ist, einen Namen/Variable in einem bestimmten Bereich neu zuzuweisen, ohne dass Funktionen explizit in diesem Bereich definiert werden müssen:
class ByRef:
def __init__(self, locs, name):
self._locs = locs
self._name = name
def set(self, val):
self._locs[self._name] = val
def get(self):
return self._locs[self._name]
def remove(self):
del self._locs[self._name]
wrapped = property(get, set, remove)
def change(x):
x.wrapped = 7
def test_me():
x = 6
print(x)
change(ByRef(locals(), "x"))
print(x)
Hier wird die ByRef
Klasse umhüllt einen Wörterbuchzugriff. So kann der Attributzugriff auf wrapped
wird in einen Elementzugriff im übergebenen Wörterbuch übersetzt. Durch die Übergabe des Ergebnisses der eingebauten locals
und dem Namen einer lokalen Variable, wird auf eine lokale Variable zugegriffen. Die Python-Dokumentation ab 3.5 rät, dass das Ändern des Wörterbuchs möglicherweise nicht funktioniert, aber es scheint für mich zu funktionieren.
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.