3290 Stimmen

Wie übergebe ich eine Variable per Referenz?

Werden die Parameter als Referenz oder als Wert übergeben? Wie übergebe ich per Referenz, so dass der folgende Code Folgendes ausgibt 'Changed' anstelle von 'Original' ?

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change(self.variable)
        print(self.variable)

    def change(self, var):
        var = 'Changed'

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.

4voto

mARK bLOORE Punkte 158

In Anbetracht der Art und Weise, wie Python mit Werten und Verweisen auf sie umgeht, ist die einzige Möglichkeit, auf ein beliebiges Instanzattribut zu verweisen, der Name:

class PassByReferenceIsh:
    def __init__(self):
        self.variable = 'Original'
        self.change('variable')
        print self.variable

    def change(self, var):
        self.__dict__[var] = 'Changed'

In echtem Code würden Sie natürlich eine Fehlerprüfung bei der Diktatsuche hinzufügen.

4voto

Liakos Punkte 374

Da Dictionaries per Referenz übergeben werden, können Sie eine dict-Variable verwenden, um darin referenzierte Werte zu speichern.

# returns the result of adding numbers `a` and `b`
def AddNumbers(a, b, ref): # using a dict for reference
    result = a + b
    ref['multi'] = a * b # reference the multi. ref['multi'] is number
    ref['msg'] = "The result: " + str(result) + " was nice!"
    return result

number1 = 5
number2 = 10
ref = {} # init a dict like that so it can save all the referenced values. this is because all dictionaries are passed by reference, while strings and numbers do not.

sum = AddNumbers(number1, number2, ref)
print("sum: ", sum)             # the returned value
print("multi: ", ref['multi'])  # a referenced value
print("msg: ", ref['msg'])      # a referenced value

3voto

textshell Punkte 1366

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.

3voto

Jesse Hogan Punkte 2877

Da Ihr Beispiel zufällig objektorientiert ist, könnten Sie die folgende Änderung vornehmen, um ein ähnliches Ergebnis zu erzielen:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change('variable')
        print(self.variable)

    def change(self, var):
        setattr(self, var, 'Changed')

# o.variable will equal 'Changed'
o = PassByReference()
assert o.variable == 'Changed'

2 Stimmen

Obwohl das funktioniert. Es handelt sich nicht um eine Referenzübergabe. Es ist eine "Übergabe durch Objektreferenz".

3voto

sergzach Punkte 6232

Sie können einfach Folgendes verwenden eine leere Klasse als Instanz zum Speichern von Referenzobjekten, da die Objektattribute intern in einem Instanzwörterbuch gespeichert werden. Siehe das Beispiel.

class RefsObj(object):
    "A class which helps to create references to variables."
    pass

...

# an example of usage
def change_ref_var(ref_obj):
    ref_obj.val = 24

ref_obj = RefsObj()
ref_obj.val = 1
print(ref_obj.val) # or print ref_obj.val for python2
change_ref_var(ref_obj)
print(ref_obj.val)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X