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.

2voto

Alok Garg Punkte 164

Pass-By-Reference in Python unterscheidet sich deutlich von dem Konzept der Pass-By-Reference in C++/Java.

  • Java&C#: Primitive Typen (einschließlich String) werden als Wert (Kopie) übergeben, Referenztypen werden als Referenz (Adresskopie) übergeben, so dass alle Änderungen am Parameter in der aufgerufenen Funktion für den Aufrufer sichtbar sind.
  • C++: Sowohl die Übergabe per Verweis als auch die Übergabe per Wert sind zulässig. Wenn ein Parameter per Verweis übergeben wird, können Sie ihn entweder ändern oder nicht, je nachdem, ob der Parameter als const oder nicht übergeben wurde. Ob const oder nicht, der Parameter behält den Verweis auf das Objekt bei, und der Verweis kann nicht zugewiesen werden, um auf ein anderes Objekt innerhalb der aufgerufenen Funktion zu zeigen.
  • Python: Python ist "pass-by-object-reference", von dem es oft heißt: "Objektreferenzen werden als Wert übergeben."[Lesen Sie hier] 1 . Sowohl der Aufrufer als auch die Funktion beziehen sich auf dasselbe Objekt, aber der Parameter in der Funktion ist eine neue Variable, die nur eine Kopie des Objekts im Aufrufer enthält. Wie in C++ kann ein Parameter in der Funktion entweder geändert werden oder nicht - dies hängt vom Typ des übergebenen Objekts ab. z.B. kann ein unveränderlicher Objekttyp in der aufgerufenen Funktion nicht geändert werden, während ein veränderliches Objekt entweder aktualisiert oder neu initialisiert werden kann. Ein entscheidender Unterschied zwischen der Aktualisierung und der Neuzuweisung/Reinitialisierung der veränderlichen Variablen besteht darin, dass der aktualisierte Wert in die aufgerufene Funktion zurückgespiegelt wird, während der reinitialisierte Wert dies nicht tut. Der Geltungsbereich jeder Zuweisung eines neuen Objekts an eine veränderbare Variable ist lokal für die Funktion in Python. Die Beispiele von @blair-conrad sind gut geeignet, um dies zu verstehen.

2 Stimmen

Alt, aber ich fühle mich verpflichtet, ihn zu korrigieren. Strings werden sowohl in Java als auch in C# per Referenz übergeben, NICHT per Wert

1 Stimmen

Nein. In c# wird alles als Wert übergeben. Es ist, dass der Wert der Variablen, die ein Objekt in c# ist genau und Heap-ID/Adresse des Objekts ist. Wenn Sie also etwas in einer Funktion auf ein neues Objekt setzen, setzen Sie die Variable in der Funktion auf die Adresse. Die Übergabe per Referenz bedeutet die Übergabe einer Adresse an einen Wert, der bei Strukturtypen eine Adresse für den Wert ist, bei Objekten jedoch eine Adresse für einen Zeiger.

0 Stimmen

Ich weiß, Sie sind Experte, wenn Sie sagten, Adresse kopieren (deshalb ref existieren), die den Verweis übergeben es selbst nicht die Kopie in C #

1voto

Julian wandhoven Punkte 250

Alternativ können Sie auch ctypes verwenden, was etwa so aussehen würde

import ctypes

def f(a):
    a.value=2398 ## resign the value in a function

a = ctypes.c_int(0)
print("pre f", a)
f(a)
print("post f", a)

da a ein c int und kein python integer ist und anscheinend per Referenz übergeben wird. Sie müssen jedoch vorsichtig sein, da seltsame Dinge passieren könnten und daher nicht empfohlen wird

1voto

Was ist mit Datenklassen ? Außerdem können Sie damit eine Typbeschränkung (auch bekannt als "Typ-Hinweis") anwenden.

from dataclasses import dataclass

@dataclass
class Holder:
    obj: your_type # Need any type? Use "obj: object" then.

def foo(ref: Holder):
    ref.obj = do_something()

Ich stimme mit den Leuten überein, dass es in den meisten Fällen besser ist, sie nicht zu verwenden.

Und doch, wenn wir über Kontexte es lohnt sich, das zu wissen.

Sie können jedoch eine explizite Kontextklasse entwerfen. Beim Prototyping bevorzuge ich Datenklassen, nur weil es einfach ist, sie hin und her zu serialisieren.

Zum Wohl!

0 Stimmen

1,9 Millionen Aufrufe und 13 Jahre später wird eine vernünftige Lösung gefunden. Ich habe sie implementiert, indem ich den Holder "State" nannte und einen booleschen Wert hinzufügte, der nun in einer anderen Funktion geändert werden kann ... ausgezeichnet und sauber!

1voto

Magnus Punkte 1318

Ich bin neu in Python, habe gestern angefangen (obwohl ich seit 45 Jahren programmiere).

Ich bin hierher gekommen, weil ich eine Funktion geschrieben habe, bei der ich zwei so genannte Out-Parameter haben wollte. Wenn es nur ein Out-Parameter gewesen wäre, würde ich mich jetzt nicht damit aufhalten, zu prüfen, wie Referenz/Wert in Python funktioniert. Ich hätte stattdessen einfach den Rückgabewert der Funktion verwendet. Aber da ich benötigte zwei Ich hatte das Gefühl, dass ich das in Ordnung bringen musste.

In diesem Beitrag werde ich zeigen, wie ich meine Situation gelöst habe. Vielleicht können andere, die hierher kommen, es wertvoll finden, auch wenn es nicht genau eine Antwort auf die Frage zum Thema ist. Erfahrene Python-Programmierer kennen die Lösung, die ich verwendet habe, natürlich schon, aber für mich war sie neu.

Aus den Antworten hier konnte ich schnell erkennen, dass Python in dieser Hinsicht ein bisschen wie Javascript funktioniert und dass man Workarounds verwenden muss, wenn man die Referenzfunktionalität möchte.

Aber dann habe ich etwas Tolles in Python gefunden, das ich in anderen Sprachen noch nicht gesehen habe, nämlich dass man mehr als einen Wert aus einer Funktion zurückgeben kann, und zwar einfach durch Komma getrennt, wie hier:

def somefunction(p):
    a=p+1
    b=p+2
    c=-p
    return a, b, c

und dass man das auf der aufrufenden Seite ähnlich handhaben kann, etwa so

x, y, z = somefunction(w)

Das war gut genug für mich und ich war zufrieden. Ich brauchte keine Abhilfe zu schaffen.

In anderen Sprachen kann man natürlich auch viele Werte zurückgeben, aber dann meist in Form eines Objekts, und man muss die aufrufende Seite entsprechend anpassen.

Die Python-Methode war schön und einfach.

Wenn Sie Folgendes nachahmen möchten durch Verweis noch mehr, könnten Sie wie folgt vorgehen:

def somefunction(a, b, c):
    a = a * 2
    b = b + a
    c = a * b * c
    return a, b, c

x = 3
y = 5
z = 10
print(F"Before : {x}, {y}, {z}")

x, y, z = somefunction(x, y, z)

print(F"After  : {x}, {y}, {z}")

was zu folgendem Ergebnis führt

Before : 3, 5, 10  
After  : 6, 11, 660

4 Stimmen

"Aber dann habe ich etwas Tolles in Python entdeckt, das ich in anderen Sprachen noch nicht gesehen habe, nämlich, dass man mehr als einen Wert aus einer Funktion zurückgeben kann" Nein, das geht nicht. Was Sie tun, ist, einen einzigen Wert zurückzugeben, einen tuple was der Ausdruck a, b, c schafft. Sie verwenden dann iteratives Entpacken um dieses Tupel in separate Variablen zu entpacken. Natürlich können Sie dies als "Rückgabe mehrerer Werte" betrachten, aber das tun Sie eigentlich nicht, sondern Sie geben einen Container zurück.

2 Stimmen

@juanpa.arrivillaga, ja, das war mir bewusst, als ich meine Antwort schrieb, ich hatte gerade darüber gelesen. Aber ich habe das Ganze nur praktisch beschrieben, ohne auf die Details einzugehen, wie es funktioniert, und meine Antwort unnötig in die Länge zu ziehen. Man kann in der Tat mehrere Werte aus einer Funktion zurückgeben, wenn dies in einem Objekt oder ähnlichem geschieht, z. B. in einem Tupel (was in Python auf die von mir gezeigte Art und Weise erledigt wird). Wenn ich bei einer Firma etwas bestelle, kann sie mir mehrere Dinge schicken, auch wenn alles in einem Paket ist.

0voto

Jop Knoppers Punkte 543

Höchstwahrscheinlich nicht die zuverlässigste Methode, aber dies funktioniert, denken Sie daran, dass Sie die eingebaute str-Funktion überladen, die in der Regel etwas ist, das Sie nicht tun wollen:

import builtins

class sstr(str):
    def __str__(self):
        if hasattr(self, 'changed'):
            return self.changed

        return self

    def change(self, value):
        self.changed = value

builtins.str = sstr

def change_the_value(val):
    val.change('After')

val = str('Before')
print (val)
change_the_value(val)
print (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