72 votes

L'émulation de passer par valeur, le comportement en python

Je tiens à imiter le passage par valeur, le comportement en python. En d'autres termes, je voudrais assurez-vous que la fonction que j'écris ne modifiez pas les données fournies par les utilisateurs.

Une façon est d'utiliser copie en profondeur:

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

est-il plus efficace ou plus pythonic moyen d'atteindre cet objectif, en faisant le moins d'hypothèses possibles sur l'objet passé (tels que .méthode clone ())

Modifier

Je suis conscient que, techniquement, tout en python est passé par valeur. J'ai été intéressé par l'émulation du comportement, c'est à dire faire en sorte que je ne plaisante pas avec les données qui ont été transmis à la fonction. Je suppose que la manière la plus générale est de cloner l'objet en question, soit avec ses propres clone mécanisme ou avec propriétédeepcopy.

44voto

dF. Points 29787

Il n'y a pas de pythonic moyen de le faire.

Python fournit très peu d'installations pour appliquer des choses comme privé ou de données en lecture seule. Le pythonic philosophie est que "nous sommes tous des adultes consentants": dans ce cas, cela signifie que "la fonction ne doit pas modifier les données" est la partie de la spec, mais pas appliquées dans le code.


Si vous voulez faire une copie des données, le plus proche que vous pouvez obtenir est votre solution. Mais copy.deepcopy, en plus d'être inefficace, a également des avertissements tels que:

Parce que copie en profondeur des copies de tout ce qu'il peut copier de trop, par exemple, d'administration des structures de données qui doit être partagé, même entre les copies.

[...]

Ce module ne permet pas de copier les types de module, la méthode, la trace de la pile, pile image, fichier, socket, fenêtre, tableau, ou des types similaires.

Donc, je ne pourrais que vous le recommandons si vous savez que vous avez affaire avec Python intégrée types ou vos propres objets (où vous pouvez personnaliser la copie de comportement en définissant l' __copy__ / __deepcopy__ méthodes spéciales, il n'y a pas besoin de définir votre propre clone() méthode).

35voto

Skurmedel Points 9227

Vous pouvez faire un décorateur et mettre le clonage comportement qui.

>>> 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

Ce n'est pas le plus robuste, et ne gère pas les clé-valeur des arguments ou des méthodes de la classe (manque d'argument), mais vous obtenez l'image.

Notez que les énoncés suivants sont équivalents:

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

Vous pourriez même avoir le décorateur prendre une sorte de fonction qui fait le clonage et permettant ainsi à l'utilisateur de le décorateur de décider de la stratégie de clonage. Dans ce cas, le décorateur est probablement la meilleure mise en œuvre en classe avec __call__ substituée.

15voto

user695800 Points 30

Il ya seulement un couple de builtin typs qui fonctionnent comme des références, comme list, par exemple.

Donc, pour moi, le pythonic façon de faire un passage par valeur, pour la liste, dans cet exemple, serait:

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

list1[:] crée une nouvelle instance de la liste 1, et vous pouvez l'affecter à une variable.

Peut-être que vous pourriez écrire une fonction qui peut recevoir un argument, puis vérifier son type, et selon que resulta, effectuer un builtin opération qui pourrait renvoyer une nouvelle instance de l'argument passé.

Comme je l'ai dit plus tôt, il y a seulement quelques builtin types, que leur comportement est comme des références, des listes dans cet exemple.

De toute façon... j'espère que ça aide.

4voto

Tom Points 1051

généralement lors de la transmission des données à un API externe, vous pouvez assurer l'intégrité de vos données en le passant comme un objet immuable, par exemple envelopper vos données dans un tuple. Ce ne peut pas être modifié, si c'est ce que vous avez essayé de l'empêcher, par votre code.

3voto

Sake Points 1549

Je ne peux pas comprendre tout autre pythonic option. Mais personnellement, je préfère le plus OO façon.

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

def f(data):
  #do stuff

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X