Pergunta

Gostaria de emular o comportamento passagem por valor em python. Em outras palavras, eu gostaria de fazer absolutamente certo de que a gravação função que eu não modifique os dados fornecidos pelo usuário.

Uma forma possível é a utilização de cópia profunda:

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

há mais eficiente ou mais pythônico maneira de alcançar este objetivo, fazendo o mínimo de suposições quanto possível sobre o objeto que está sendo passado (como .clone () método)

Editar

Estou ciente de que tecnicamente tudo em python é passado por valor. Eu estava interessado em emulação o comportamento, ou seja, ter certeza que eu não mexer com os dados que foram passados ??para a função. Eu acho que a maneira mais geral é clonar o objeto em questão, quer com o seu próprio mecanismo de clone ou com deepcopy.

Foi útil?

Solução

Não há nenhuma maneira Python de fazer isso.

Python fornece muito poucas instalações para enforcing coisas tais como dados pessoais ou somente leitura. A filosofia pythônico é que "nós somos todos adultos responsáveis": neste caso, isso significa que "a função não deve mudar a data" é parte da especificação, mas não aplicadas no código.


Se você quiser fazer uma cópia dos dados, o mais próximo que você pode obter é a sua solução. Mas copy.deepcopy, além de ser ineficiente, também tem ressalvas como :

Porque cópia profunda copia tudo pode copiar muito, por exemplo, estruturas de dados administrativos que devem ser compartilhados, mesmo entre as cópias.

[...]

Este módulo não copia tipos como módulo, método, rastreamento de pilha, quadro de pilha, arquivo, socket, janela, array, ou quaisquer outros tipos similares.

Então, eu só recomendo-o se você sabe que você está lidando com built-in tipos Python ou seus próprios objetos (onde você pode personalizar a cópia de comportamento, definindo os métodos __copy__ / __deepcopy__ especiais, não há necessidade de definir o seu método clone() próprio).

Outras dicas

Você pode fazer um decorador e colocar o comportamento clonagem nisso.

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

Esta não é a forma mais robusta, e não lidar com argumentos chave-valor ou métodos de classe (falta de auto argumento), mas você começa a foto.

Note-se que as seguintes afirmações são iguais:

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

Você poderia mesmo ter o decorador tomar algum tipo de função que faz a clonagem e permitindo assim que o usuário do decorador para decidir a estratégia de clonagem. Nesse caso, o decorador é provavelmente o melhor implementado como uma classe com __call__ substituído.

Há apenas um par de typs embutidas que funcionam como referências, como list, por exemplo.

Então, para mim a maneira Python para fazer uma passagem por valor, por lista, neste exemplo, seria:

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

list1[:] cria uma nova instância do list1, e você pode atribuí-lo a uma nova variável.

Talvez você poderia escrever uma função que poderia receber um argumento, em seguida, verificar o seu tipo, e de acordo que Resulta, executar uma operação builtin que poderia retornar uma nova instância do argumento passado.

Como eu disse anteriormente, há apenas alguns tipos internos, que seu comportamento é como referências, listas neste exemplo.

De qualquer forma ... espero que ajude.

Normalmente, quando passar os dados para uma API externa, você pode assegurar a integridade dos seus dados passando-lo como um objeto imutável, por exemplo envolver seus dados em uma tupla. Isso não pode ser modificado, se é isso que você tentou evitar por seu código.

Eu não consigo descobrir qualquer outro pythônico opção. Mas pessoalmente eu prefiro o mais OO caminho.

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

def f(data):
  #do stuff

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

Embora eu tenho certeza que não há realmente maneira Python para fazer isso, espero que o módulo pickle lhe dará cópias de tudo o que qualquer negócio que tratam como um valor.

import pickle

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

Na sequência da do user695800 resposta, passar por valor para as listas de possíveis com o [:] operador

def listCopy(l):
    l[1] = 5
    for i in l:
        print i

chamado com

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

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

list1
Out[14]: [1, 2, 3, 4]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top