Frage

Ich möchte das Pass-by-Wert Verhalten in Python emulieren. Mit anderen Worten, würde Ich mag absolut sicher machen, dass die Funktion schreibe ich nicht ändern Benutzerdaten geliefert.

Eine Möglichkeit ist tiefe Kopie zu verwenden:

from copy import deepcopy
def f(data):
    data = deepcopy(data)
    #do stuff

ist es effizienter oder pythonic Weg, um dieses Ziel zu erreichen, so wenig Annahmen wie möglich zu machen über das Objekt (zB .clone () -Methode) geleitet wird

Bearbeiten

Ich bin mir bewusst, dass technisch alles in Python von Wert übergeben wird. Ich war interessiert in Emulations das Verhalten, das heißt dafür, dass ich nicht mit Zohan an den Daten, die an die Funktion übergeben wurden. Ich denke, die allgemeinste Art und Weise ist es, das betreffende Objekt zu klonen entweder mit einem eigenen Klon-Mechanismus oder mit deep.

War es hilfreich?

Lösung

Es gibt keine pythonic Art und Weise, dies zu tun.

Python bietet nur sehr wenige Einrichtungen für Erzwingen Dinge wie private oder Nur-Lese-Daten. Die pythonic Philosophie ist, dass „uns alle mündig Erwachsene“: In diesem Fall bedeutet dies, dass „die Funktion soll nicht die Daten ändern“ Teil der Spezifikation ist aber nicht im Code erzwungen.


Wenn Sie eine Kopie der Daten machen möchten, können in der Nähe bekommen Sie Ihre Lösung. Aber copy.deepcopy neben ineffizient, auch Einsprüche hat wie :

  

Da tiefere Kopie kopiert alles, was es kann zu viel kopieren, zum Beispiel Verwaltungsdatenstrukturen, die auch zwischen den Kopien geteilt werden sollten.

     

[...]

     

Dieses Modul kopiert nicht Typen wie Modul, Verfahren, Stack-Trace, Stack-Frame, Datei, Sockel, Fenster, ein Array oder ähnliche Typen.

Also ich nur würde es empfehlen, wenn Sie wissen, dass Sie mit einer in denen es zu tun Python-Typen oder Ihre eigenen Objekten (in dem Sie Kopierverhalten durch die Definition der __copy__ / __deepcopy__ speziellen Methoden anpassen können, gibt es keine Notwendigkeit zu definieren, Ihre eigene clone() Methode).

Andere Tipps

Sie können einen Dekorateur machen und das Klonen Verhalten, dass setzen.

>>> 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 Art und Weise, und nicht verarbeitet Schlüssel-Wert-Argumente oder Klassenmethoden (Mangel an Selbst Argumente), aber Sie erhalten das Bild.

Beachten Sie, dass die folgenden Aussagen sind gleich:

@somedecorator
def func1(): pass
# ... same as ...
def func2(): pass
func2 = somedecorator(func2)

könnten Sie haben sogar den Dekorateur eine Art von Funktion übernehmen, die das Klonen funktioniert und so dass der Benutzer des Dekorateur die Klonierungsstrategie zu entscheiden. In diesem Fall ist der Dekorateur wahrscheinlich am besten als eine Klasse mit __call__ überschrieben umgesetzt werden.

Es gibt nur ein paar gebautet typen, die als Referenzen zu arbeiten, wie list, zum Beispiel.

Also, für mich die Art und Weise pythonic eine Pass-by-Wert, Liste zu tun, in diesem Beispiel wäre:

list1 = [0,1,2,3,4]
list2 = list1[:]

list1[:] erstellt eine neue Instanz des list1, und Sie können es zu einem neuen Variablen zuweisen.

Vielleicht könnten Sie eine Funktion schreiben, die ein Argument empfangen konnten, dann seine Art überprüfen, und nach, dass resulta, eine eingebaute Operation durchführen, die vergangen eine neue Instanz des Arguments zurückkehren konnte.

Wie ich bereits sagte, gibt es nur wenige eingebaute Typen, dass ihr Verhalten wie Referenzen, Listen in diesem Beispiel ist.

Jede Art und Weise ... hoffe, es hilft.

in der Regel, wenn die Daten an eine externe API geben, können Sie die Integrität Ihrer Daten sicherzustellen, indem sie sie als unveränderliche Objekt, zum Beispiel wickeln Sie Ihre Daten in ein Tupel übergeben. Dies kann nicht geändert werden, wenn es das ist, was Sie von Ihrem Code zu verhindern versucht.

Ich kann nicht herausfinden, andere pythonic Option. Aber ich persönlich würde das mehr bevorzugen OO Art und Weise.

class TheData(object):
  def clone(self):  """return the cloned"""

def f(data):
  #do stuff

def caller():
  d = TheData()
  f(d.clone())

Obwohl ich sicher bin, gibt es keine wirklich pythonic Weg, dies zu tun, erwarte ich, dass die pickle Modul erhalten Sie Kopien von allem haben Sie jedes Unternehmen als Wert zu behandeln.

import pickle

def f(data):
    data = pickle.loads(pickle.dumps((data)))
    #do stuff

Im Anschluss an 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

genannt mit

In [12]: list1 = [1,2,3,4]

In [13]: listCopy(list1[:])
1
5
3
4

list1
Out[14]: [1, 2, 3, 4]
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top