在python中模拟值传递行为
我想在python中模拟值传递行为。换句话说,我希望绝对确保我编写的函数不会修改用户提供的数据 一种可能的方法是使用深度复制:在python中模拟值传递行为,python,pass-by-value,Python,Pass By Value,我想在python中模拟值传递行为。换句话说,我希望绝对确保我编写的函数不会修改用户提供的数据 一种可能的方法是使用深度复制: from copy import deepcopy def f(data): data = deepcopy(data) #do stuff 是否有更有效或更具python风格的方法来实现这一目标,尽可能少地假设所传递的对象(例如.clone()方法) 编辑 我知道从技术上讲,python中的所有内容都是按值传递的。我感兴趣的是模拟行为,即确保不会弄乱
from copy import deepcopy
def f(data):
data = deepcopy(data)
#do stuff
是否有更有效或更具python风格的方法来实现这一目标,尽可能少地假设所传递的对象(例如.clone()方法)
编辑
我知道从技术上讲,python中的所有内容都是按值传递的。我感兴趣的是模拟行为,即确保不会弄乱传递给函数的数据。我想最常用的方法是使用自己的克隆机制或使用deepcopy克隆有问题的对象。我想不出任何其他pythonic选项。但就我个人而言,我更喜欢更糟糕的方式
您可以制作一个装饰器,并将克隆行为放入其中
>>> 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)
您甚至可以让decorator执行某种克隆功能,从而允许decorator的用户决定克隆策略。在这种情况下,decorator最好是作为一个类来实现,并覆盖
\uuuu调用
。没有pythonic方法可以做到这一点
Python很少提供强制执行私有或只读数据之类的功能。python的哲学是“我们都是同意的成年人”:在这种情况下,这意味着“函数不应该更改数据”是规范的一部分,但不是在代码中强制执行的
如果你想复制数据,你能得到的最接近的就是你的解决方案。但是
copy.deepcopy
,除了效率低下之外,还有一些警告:
因为深度复制会复制所有内容,所以它可能会复制太多内容,例如,即使在副本之间也应该共享的管理数据结构
[……]
此模块不复制诸如模块、方法、堆栈跟踪、堆栈帧、文件、套接字、窗口、数组或任何类似类型的类型
因此,我只建议您在处理内置Python类型或您自己的对象时使用它(您可以通过定义
\uuuuu copy\uuuuu
/\uuu deepcopy\uuuu
特殊方法自定义复制行为,无需定义您自己的clone()
方法)。通常在将数据传递到外部API时,您可以通过将数据作为不可变对象传递来确保数据的完整性,例如,将数据包装到元组中。这是无法修改的,如果这是您试图通过代码来阻止的。虽然我确信没有真正的python方法来做到这一点,但我希望pickle
模块将为您提供所有业务视为价值的副本
import pickle
def f(data):
data = pickle.loads(pickle.dumps((data)))
#do stuff
例如,
list
,只有几个内置类型可以用作引用
因此,对于我来说,在本例中,执行传递值for list的python方法是:
list1 = [0,1,2,3,4]
list2 = list1[:]
list1[:]
创建list1的新实例,您可以将其分配给新变量
也许您可以编写一个函数来接收一个参数,然后检查其类型,并根据该结果执行一个内置操作,该操作可以返回所传递参数的新实例
如前所述,只有少数内置类型,它们的行为类似于本例中的引用和列表
无论如何。。。希望有帮助。关于用户695800的答案,请通过[:]运算符传递列表的值
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]
许多人使用标准库。我更喜欢在我的类中定义
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
或\uuuuuuuuuuuuuuuuuuu。copy
中的方法可能存在一些问题
浅层副本将保留对原始对象的引用,而不是创建新对象李>
deepcopy将递归运行,有时可能导致死循环。如果没有足够的注意力,记忆可能会爆炸
要避免这些失控行为,请通过覆盖\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
和\uuuuuuuuuuuuuuuuuuuuuuuuuuuu。举个好例子 多谢各位。然而,克隆意味着一种定制的、可能更有效的深度复制方式。我个人看到库中的克隆对象没有预期的那么深:)。更不用说没有克隆方法的类了。因此,基本上deepcopy更具可移植性。(请参阅我对问题的澄清)deepcopy只是克隆数据的另一种方式。在我的代码中真正的一点是,“在调用方内部”确实是决定如何传递参数的更好的地方,而不是在函数内部。所以deepcopy绝对不是“更有效的”。当克隆数据的决定发生在调用方中,并且您确切地知道要传递的数据类型时,那么您可以使用最有效的方法来实现这一点;(如列表[:],目录(dic))。。如果您不确定将传递哪些数据,那么将高效克隆方法的决策保留在数据对象本身将始终产生更好的性能。我是否理解您的意思,clone()/deepcopy()应该与数据结构驻留在一起。然后使用调用方方法来获得传递的函数f?(在这种情况下,caller(f)
中缺少f
参数)您不需要先知道函数的签名吗?你能把它变成一般的多元变量吗?还是为每个函数实现一个新的数据结构?或者将每个函数定义为每个数据对象的成员函数?您已经做对了。只是一个术语说明:Python已经使用了传递值。许多值恰好是引用,所以您要按值传递引用。如果Python使用通过引用传递,那么def(x):x=5
In [12]: list1 = [1,2,3,4]
In [13]: listCopy(list1[:])
1
5
3
4
list1
Out[14]: [1, 2, 3, 4]