Ich möchte das Pass-by-Value-Verhalten in Python emulieren. Mit anderen Worten, ich möchte unbedingt sicherstellen, dass die von mir geschriebene Funktion die vom Benutzer bereitgestellten Daten nicht ändert.
Eine Möglichkeit ist die Verwendung einer tiefen Kopie:
from copy import deepcopy
def f(data):
data = deepcopy(data)
#do stuff
Gibt es einen effizienteren oder pythonischeren Weg, um dieses Ziel zu erreichen, indem so wenig Annahmen wie möglich über das übergebene Objekt getroffen werden (z. B. die .clone () -Methode)?
Bearbeiten
Mir ist bewusst, dass technisch alles in Python als Wert übergeben wird. Ich war daran interessiert, das Verhalten zu emulieren , dh sicherzustellen, dass ich nicht mit den Daten herumspiele, die an die Funktion übergeben wurden. Ich denke, der allgemeinste Weg besteht darin, das betreffende Objekt entweder mit einem eigenen Klonmechanismus oder mit Deepcopy zu klonen.
quelle
Antworten:
Es gibt keinen pythonischen Weg, dies zu tun.
Python bietet nur sehr wenige Möglichkeiten, um beispielsweise private oder schreibgeschützte Daten durchzusetzen . Die pythonische Philosophie lautet: "Wir sind alle einverstanden mit Erwachsenen": In diesem Fall bedeutet dies, dass "die Funktion die Daten nicht ändern sollte" Teil der Spezifikation ist, aber nicht im Code erzwungen wird.
Wenn Sie eine Kopie der Daten erstellen möchten, ist Ihre Lösung die nächstgelegene. Aber es
copy.deepcopy
ist nicht nur ineffizient, sondern hat auch Vorbehalte wie :Daher würde ich es nur empfehlen, wenn Sie wissen, dass Sie mit integrierten Python-Typen oder Ihren eigenen Objekten arbeiten (wo Sie das Kopierverhalten durch Definieren der
__copy__
/__deepcopy__
special-Methoden anpassen können, müssen Sie keine eigeneclone()
Methode definieren ).quelle
Sie können einen Dekorateur erstellen und das Klonverhalten darin einfügen.
>>> def passbyval(func): def new(*args): cargs = [deepcopy(arg) for arg in args] return func(*cargs) return new >>> @passbyval def myfunc(a): print a >>> myfunc(20) 20
Dies ist nicht die robusteste Methode und behandelt keine Schlüsselwertargumente oder Klassenmethoden (fehlendes Selbstargument), aber Sie erhalten das Bild.
Beachten Sie, dass die folgenden Aussagen gleich sind:
@somedecorator def func1(): pass # ... same as ... def func2(): pass func2 = somedecorator(func2)
Sie können sogar festlegen, dass der Dekorateur eine Funktion übernimmt, die das Klonen ausführt, sodass der Benutzer des Dekorateurs die Klonstrategie festlegen kann. In diesem Fall wird der Dekorateur wahrscheinlich am besten als Klasse mit
__call__
überschriebenen implementiert .quelle
Es gibt nur einige integrierte Typen, die beispielsweise als Referenz dienen
list
.Für mich wäre die pythonische Methode zum Ausführen eines Pass-by-Value für die Liste in diesem Beispiel:
list1 = [0,1,2,3,4] list2 = list1[:]
list1[:]
Erstellt eine neue Instanz der Liste1, und Sie können sie einer neuen Variablen zuweisen.Vielleicht könnten Sie eine Funktion schreiben, die ein Argument empfangen könnte, dann ihren Typ überprüfen und gemäß diesem Ergebnis eine eingebaute Operation ausführen, die eine neue Instanz des übergebenen Arguments zurückgeben könnte.
Wie ich bereits sagte, gibt es nur wenige integrierte Typen, deren Verhalten wie Referenzen ist, Listen in diesem Beispiel.
Wie auch immer ... hoffe es hilft.
quelle
Wenn Sie Daten an eine externe API übergeben, können Sie normalerweise die Integrität Ihrer Daten sicherstellen, indem Sie sie als unveränderliches Objekt übergeben, z. B. Ihre Daten in ein Tupel einschließen. Dies kann nicht geändert werden, wenn Sie dies durch Ihren Code verhindert haben.
quelle
Ich kann keine andere pythonische Option finden. Aber persönlich würde ich den OO- Weg bevorzugen .
class TheData(object): def clone(self): """return the cloned""" def f(data): #do stuff def caller(): d = TheData() f(d.clone())
quelle
f
fehlt der Parametercaller(f)
.) Müssen Sie nicht zuerst die Signatur der Funktion kennen? Können Sie es generisch multivariat machen? Oder implementieren Sie für jede Funktion eine neue Datenstruktur? Oder definieren Sie jede Funktion als Elementfunktion für jedes Datenobjekt?Obwohl ich sicher bin, dass es keinen wirklich pythonischen Weg gibt, dies zu tun, erwarte ich, dass das
pickle
Modul Ihnen Kopien von allem gibt, was Sie als Wert behandeln.import pickle def f(data): data = pickle.loads(pickle.dumps((data))) #do stuff
quelle
Weiter user695800 die Antwort, vorbei Wert für Listen möglich mit dem [:] Operator
def listCopy(l): l[1] = 5 for i in l: print i
angerufen mit
In [12]: list1 = [1,2,3,4] In [13]: listCopy(list1[:]) 1 5 3 4 list1 Out[14]: [1, 2, 3, 4]
quelle
Viele Menschen nutzen die Standard - Bibliothek kopieren . Ich definiere lieber
__copy__
oder__deepcopy__
in meinen Klassen. Die Methoden incopy
können einige Probleme haben.Um diese außer Kontrolle geratenen Verhaltensweisen zu vermeiden, definieren Sie Ihre eigenen flachen / tiefen Kopiermethoden durch Überschreiben
__copy__
und__deepcopy__
. Und Alex 'Antwort gibt ein gutes Beispiel.quelle