Эмуляция поведения передачи по значению в python



Я хотел бы эмулировать поведение pass-by-value в python. Другими словами, Я хотел бы абсолютно убедиться, что функция, которую я пишу, не изменяет предоставленные пользователем данные.



один из возможных способов - использовать глубокое копирование:



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


есть ли более эффективные или более весть способ достижения этой цели, делая как можно меньше предположений о передаваемом объекте (например .метод clone ())



Edit



Я знаю, что технически все в python передается по значению. Я был заинтересован в эмуляция поведение, т. е. убедившись, что я не связываюсь с данными, которые были переданы в функцию. Я думаю, что самый общий способ-клонировать объект, о котором идет речь, либо с помощью собственного механизма клонирования, либо с помощью deepcopy.

393   7  

7 ответов:

нет для Python способ сделать это.

Python предоставляет очень мало возможностей для исполнение такие вещи, как личные или только для чтения данных. Философия питона заключается в том, что "мы все согласны взрослые": в этом случае это означает, что "функция не должна изменять данные" является частью спецификации, но не применяется в коде.


если вы хотите сделать копию данных, ближайший вы можете получить это ваше решение. Но copy.deepcopy, кроме того, что неэффективно, также есть предостережения например:

потому что deep copy копирует все, что он может копировать слишком много, например, административные структуры данных, которые должны быть разделены даже между копиями.

[...]

этот модуль не копирует такие типы, как модуль, метод, трассировка стека, кадр стека, файл, сокет, окно, массив или любые подобные типы.

так что я бы только рекомендовал его, если вы знаете, что вы имеете дело с встроенные типы Python или ваши собственные объекты (где вы можете настроить поведение копирования, определив __copy__/__deepcopy__ специальные методы, нет необходимости определять свой собственный clone() метод).

вы можете сделать декоратор и поставить поведение клонирования в этом.

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

Это не самый надежный способ, и не обрабатывает аргументы ключа-значения или методы класса (отсутствие собственного аргумента), но вы получаете картину.

обратите внимание, что следующие утверждения равны:

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

вы могли бы даже иметь декоратор взять какую-то функцию, которая делает клонирование и, таким образом, позволяя пользователю декоратора решить стратегию клонирования. В том case декоратор, вероятно, лучше всего реализован как класс с __call__ переопределяется.

есть только несколько встроенных типов, которые работают как ссылки, например list, например.

Итак, для меня питонический способ сделать переход по значению, для списка, в этом примере, будет:

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

list1[:] создает новый экземпляр list1, и вы можете назначить его новой переменной.

возможно, вы могли бы написать функцию, которая могла бы получить один аргумент, а затем проверить его тип и в соответствии с этим результатом выполнить встроенную операцию, которая могла бы возвращает новый экземпляр переданного аргумента.

как я уже говорил ранее, есть только несколько встроенных типов, что их поведение похоже на ссылки, списки в этом примере.

В любом случае... надеюсь, это поможет.

обычно при передаче данных во внешний API вы можете обеспечить целостность своих данных, передав их как неизменяемый объект, например, обернуть данные в кортеж. Это не может быть изменено, если это то, что вы пытались предотвратить с помощью кода.

Я не могу понять ни одного другого весть. Но лично я предпочел бы больше ОО путь.

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

def f(data):
  #do stuff

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

хотя я уверен, что нет действительно питонского способа сделать это, я ожидаю pickle модуль даст вам копии всего, что у вас есть лечение как ценность.

import pickle

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

дальше user695800 это ответ, передать по значению для списков можно с помощью оператора [:]

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

позвонил с

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

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

list1
Out[14]: [1, 2, 3, 4]

Comments

    Ничего не найдено.