为什么深层复制不会创建对lambda函数的新引用?

时间:2012-05-29 15:17:37

标签: python

在python中发现这个奇怪的东西:

class SomeClass():
    def __init__(self):
        pass

a = [SomeClass()]
b = copy.deepcopy(a)

输出:

>>> a
[<__main__.Some instance at 0x10051b1b8>]
>>> b
[<__main__.Some instance at 0x10051b092>]

这与预期一致 - deepcopy为b创建了新的SomeClass()对象。

但是,如果,

f = lambda x:x+1
a = [f]
b = copy.deepcopy(a)

我明白了:

>>> a
[<function <lambda> at 0x10056e410>]
>>> b
[<function <lambda> at 0x10056e410>]

为什么deepcopy在第二种情况下不会创建新的lambda实例?这是否意味着lambda函数是原子的?

4 个答案:

答案 0 :(得分:5)

查看第222 and 223 from the source code行:

d[types.BuiltinFunctionType] = _deepcopy_atomic
d[types.FunctionType] = _deepcopy_atomic

模块认为它们是原子的,我不知道如何改变lambda。

答案 1 :(得分:5)

这不仅适用于lambdas,也适用于没有更普遍状态的函数。

>>> def some_function(word): print word
>>> a = [some_function]
>>> a
[<function some_function at 0x1007026e0>]
>>> copy.deepcopy(a)
[<function some_function at 0x1007026e0>]

因为函数不存储状态,所以deepcopy不会为它们创建新的引用。此处记录了与此问题类似的主题的有趣讨论(尽管不完全相同):http://bugs.python.org/issue1515

答案 2 :(得分:4)

作为一些人认为lambda不可变的旁注,请注意以下行为:

>>> a = lambda x: x + 1
>>> a(12)
13
>>> b = lambda x: x - 1
>>> b(12)
11
>>> a.__code__ = b.__code__
>>> a(12)
11
>>> 

答案 3 :(得分:-1)

我不知道Python的完整历史,但是函数可能像字符串和元组一样不可变,因此最初deepcopy的行为完全合理。< / p>

另外,在实践中,大多数人更关心的是他们的数据对象被复制而不是他们的功能。 deepcopy制作函数副本的必要性是一个明显的边缘情况,并且期待受此边缘情况影响的人们推出他们自己的解决方案对我来说似乎完全没问题。

合理的方法是编写一个装饰器@copyablefunc,它将函数包装在一个可调用对象(即一个具有__call__()方法的类)中,并且还定义__copy__()和{ {1}} __deepcopy__()例程使用的方法。

deepcopy也没有真正复制类,顺便说一下。