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.

0voto

Youjun Hu Punkte 585
  1. Python weist jedem Objekt einen eindeutigen Bezeichner zu, der mit Hilfe der in Python eingebauten id() Funktion. Es ist bereit zu überprüfen, ob tatsächliche und formale Argumente in einem Funktionsaufruf denselben id-Wert haben, was darauf hinweist, dass sich das Dummy-Argument und das tatsächliche Argument auf dasselbe Objekt beziehen.

  2. Beachten Sie, dass das eigentliche Argument und das entsprechende Dummy-Argument zwei Namen sind, die sich auf dasselbe Objekt beziehen. Wenn Sie ein Dummy-Argument an einen neuen Wert/Objekt im Funktionsbereich binden, hat dies keine Auswirkungen auf die Tatsache, dass das tatsächliche Argument immer noch auf das ursprüngliche Objekt verweist, da tatsächliches Argument und Dummy-Argument zwei Namen sind.

  3. Die beiden oben genannten Tatsachen lassen sich als "Argumente werden durch Zuweisung übergeben" zusammenfassen, d.h.,

    dummy_argument = actual_argument

Wenn Sie neu binden dummy_argument zu einem neuen Objekt im Funktionsrumpf, die actual_argument bezieht sich immer noch auf das ursprüngliche Objekt. Wenn Sie dummy_argument[0] = some_thing ändern, dann wird dies auch actual_argument[0] . Daher kann die Wirkung der "Referenzübergabe" durch Änderung der Komponenten/Attribute der übergebenen Objektreferenz erzielt werden. Dies setzt natürlich voraus, dass das übergebene Objekt ein veränderbares Objekt ist.

  1. Um einen Vergleich mit anderen Sprachen anzustellen, kann man sagen, dass Python Argumente als Wert übergibt, so wie es C tut, wo man bei der Übergabe "per Referenz" tatsächlich die Referenz (d.h. den Zeiger) als Wert übergibt

-1voto

TVK Punkte 956

Ich habe eine ähnliche Anforderung wie folgt gelöst:

Um eine Mitgliedsfunktion zu implementieren, die eine Variable ändert, übergeben Sie nicht die Variable selbst, sondern eine functools.partial die Folgendes enthält setattr die sich auf die Variable bezieht. Der Aufruf der functools.partial innerhalb change() wird ausgeführt settatr und ändern Sie die tatsächliche referenzierte Variable.

Beachten Sie, dass setattr benötigt den Namen der Variablen als String.

class PassByReference(object):
    def __init__(self):
        self.variable = "Original"
        print(self.variable)        
        self.change(partial(setattr,self,"variable"))
        print(self.variable)

    def change(self, setter):
        setter("Changed")

-2voto

MacGyver Punkte 17368

Dies könnte eine elegante objektorientierte Lösung ohne diese Funktionalität in Python sein. Eine noch elegantere Lösung wäre, dass jede Klasse, die Sie erstellen, eine Unterklasse von dieser Klasse ist. Oder Sie könnten sie "MasterClass" nennen. Aber anstatt eine einzelne Variable und einen einzelnen Booleschen Wert zu haben, sollten Sie eine Art Sammlung daraus machen. Ich habe die Benennung Ihrer Instanzvariablen korrigiert, um PEP 8 zu entsprechen.

class PassByReference:
    def __init__(self, variable, pass_by_reference=True):
        self._variable_original = 'Original'
        self._variable = variable
        self._pass_by_reference = pass_by_reference # False => pass_by_value
        self.change(self.variable)
        print(self)

    def __str__(self):
        print(self.get_variable())

    def get_variable(self):
        if pass_by_reference == True:
            return self._variable
        else:
            return self._variable_original

    def set_variable(self, something):
        self._variable = something

    def change(self, var):
        self.set_variable(var)

def caller_method():

    pbr = PassByReference(variable='Changed') # this will print 'Changed'
    variable = pbr.get_variable() # this will assign value 'Changed'

    pbr2 = PassByReference(variable='Changed', pass_by_reference=False) # this will print 'Original'
    variable2 = pbr2.get_variable() # this will assign value 'Original'

0 Stimmen

Hey, soll das ein Witz sein?

-2voto

eyal0931 Punkte 31

In den meisten Fällen handelt es sich bei der per Referenz zu übergebenden Variablen um ein Klassenmitglied. Die Lösung, die ich vorschlage, ist die Verwendung eines Dekorators, um sowohl ein Feld, das veränderbar ist, als auch die entsprechende Eigenschaft hinzuzufügen. Das Feld ist ein Klassen-Wrapper um die Variable.

Le site @refproperty fügt beides hinzu self._myvar (veränderbar) und self.myvar Eigentum.

@refproperty('myvar')
class T():
    pass

def f(x):
   x.value=6

y=T()
y.myvar=3
f(y._myvar)
print(y.myvar) 

Es wird 6 gedruckt.

Vergleichen Sie dies mit:

class X:
   pass

x=X()
x.myvar=4

def f(y):
    y=6

f(x.myvar)
print(x.myvar) 

In diesem Fall wird es nicht funktionieren. Es wird 4 gedruckt.

Der Code lautet wie folgt:

def refproperty(var,value=None):
    def getp(self):
        return getattr(self,'_'+var).get(self)

    def setp(self,v):
        return getattr(self,'_'+var).set(self,v)

    def decorator(klass):
        orginit=klass.__init__
        setattr(klass,var,property(getp,setp))

        def newinit(self,*args,**kw):
            rv=RefVar(value)
            setattr(self,'_'+var,rv)
            orginit(self,*args,**kw)

        klass.__init__=newinit
        return klass
    return decorator

class RefVar(object):
    def __init__(self, value=None):
        self.value = value
    def get(self,*args):
        return self.value
    def set(self,main, value):
        self.value = value

-2voto

Celes Punkte 31
def i_my_wstring_length(wstring_input:str = "", i_length:int = 0) -> int:
    i_length[0] = len(wstring_input)
    return 0

wstring_test  = "Test message with 32 characters."
i_length_test = [0]
i_my_wstring_length(wstring_test, i_length_test)
print("The string:\n\"{}\"\ncontains {} character(s).".format(wstring_test, *i_length_test))
input("\nPress ENTER key to continue . . . ")

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