为什么deepcopy不会创建对lambda函数的新引用?

jer*_*use 13 python

在python中发现这个奇怪:

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

a = [SomeClass()]
b = copy.deepcopy(a)
Run Code Online (Sandbox Code Playgroud)

输出:

>>> a
[<__main__.Some instance at 0x10051b1b8>]
>>> b
[<__main__.Some instance at 0x10051b092>]
Run Code Online (Sandbox Code Playgroud)

这与预期一样 - deepcopy SomeClass()为b 创建了新对象.

但是,如果,

f = lambda x:x+1
a = [f]
b = copy.deepcopy(a)
Run Code Online (Sandbox Code Playgroud)

我明白了:

>>> a
[<function <lambda> at 0x10056e410>]
>>> b
[<function <lambda> at 0x10056e410>]
Run Code Online (Sandbox Code Playgroud)

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

Kar*_*mel 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>]
Run Code Online (Sandbox Code Playgroud)

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

  • 同样,函数(包括lambda;那些甚至具有相同的类型!)*是*可变的.请参阅Noctis Skytower的答案. (2认同)
  • 可能是可变的,但不是(按惯例)变异的.从上面链接的线程中的Guido vR开始,"A(bound)方法包含一个明确表示状态的实例,并且调用该方法可以很容易地改变该状态.这与类(可能包含状态)或模块(几乎肯定包含)不同状态)或函数(可能会改变全局状态) - 在所有这些情况下,我们讨论的是单例状态,为此不要创建克隆." (2认同)

Noc*_*wer 5

作为某些人认为lambda不可变的旁注,请观察以下行为:

>>> a = lambda x: x + 1
>>> a(12)
13
>>> b = lambda x: x - 1
>>> b(12)
11
>>> a.__code__ = b.__code__
>>> a(12)
11
>>> 
Run Code Online (Sandbox Code Playgroud)


Rod*_*iro 4

查看源代码中的第222和第223行:

d[types.BuiltinFunctionType] = _deepcopy_atomic
d[types.FunctionType] = _deepcopy_atomic
Run Code Online (Sandbox Code Playgroud)

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

  • 同样,函数(包括lambda;那些甚至具有相同的类型!)*是*可变的.请参阅Noctis Skytower的答案. (2认同)