我想模拟Python中的传值行为。换句话说,我想绝对确保我编写的函数不会修改用户提供的数据。
一种可能的方法是使用深复制:
from copy import deepcopy
def f(data):
data = deepcopy(data)
#do stuff
有没有更高效或更Pythonic的方法来实现这个目标,对传递的对象做出尽可能少的假设(例如
.clone()
方法)?
我知道从技术上讲,Python 中的所有内容都是按值传递的。我对“模拟”行为感兴趣,即确保我不会弄乱传递给函数的数据。我想最通用的方法是使用其自己的克隆机制或使用deepcopy
来克隆有问题的对象。
Python 提供的工具很少用于
强制执行,例如私有或只读数据。 pythonic 哲学是“我们都是同意的成年人”:在这种情况下,这意味着“函数不应该更改数据”是规范的一部分,但不在代码中强制执行。
如果您想复制数据,您可以获得的最接近的解决方案就是您的解决方案。但是copy.deepcopy
,除了效率低之外,还有一些注意事项
比如: 因为深复制会复制所有可能复制过多的内容,例如,即使在副本之间也应该共享的管理数据结构。
[...]
此模块不复制模块、方法、堆栈跟踪、堆栈帧、文件、套接字、窗口、数组或任何类似类型等类型。
所以我只推荐它,如果你知道你正在处理内置的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
这不是最稳健的方法,并且不处理键值参数或类方法(缺少 self 参数),但您明白了。
请注意以下陈述是相等的:
@somedecorator
def func1(): pass
# ... same as ...
def func2(): pass
func2 = somedecorator(func2)
您甚至可以让装饰器采用某种进行克隆的函数,从而允许装饰器的用户决定克隆策略。在这种情况下,装饰器最好实现为重写
__call__
的类。
list
。
所以,对于我来说,在这个例子中,对列表进行值传递的Python方式是:
list1 = [0,1,2,3,4]
list2 = list1[:]
list1[:]
创建 list1 的新实例,您可以将其分配给新变量。
也许您可以编写一个可以接收一个参数的函数,然后检查其类型,并根据该结果执行一项内置操作,该操作可以返回所传递参数的新实例。
正如我之前所说,只有少数内置类型,它们的行为就像本例中的引用、列表。
无论如何...希望有帮助。
选项。 但就我个人而言,我更喜欢更OO的方式。
class TheData(object):
def clone(self): """return the cloned"""
def f(data):
#do stuff
def caller():
d = TheData()
f(d.clone())
答案,通过[:]运算符可能的列表值传递
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]
pickle
模块将为您提供任何业务视为价值的所有内容的副本。
import pickle
def f(data):
data = pickle.loads(pickle.dumps((data)))
#do stuff
。我更喜欢在课堂上定义 __copy__
或
__deepcopy__
。 copy
中的方法可能存在一些问题。 浅拷贝将保留对原始对象的引用,而不是创建新的对象。
__copy__
和
__deepcopy__
来定义自己的浅/深复制方法。 Alex 的回答给出了一个很好的例子。