python - 执行 `func = func.__call__` 时 Python 会发生什么?

标签 python testing attributes crash call

我最近在 Python 中想到了一些事情:x = y(z) 等同于 x = y.__call__(z)。然而,一项测试似乎使该假设无效,并导致 Python 的解释器崩溃。

Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def ret(*args):
...     return args
...
>>> ret(1, 2, 3)
(1, 2, 3)
>>> for _ in range(1000000):
...     ret = ret.__call__
...
>>> ret(1, 2, 3)

运行第二个 ret(1, 2, 3) 会导致 Python 崩溃并返回命令提示符 ( image )。

  1. 当行 ret = ret.__call__ 执行时,后台发生了什么?
  2. 为什么 Python 在最后一行停止工作,是否应该将其报告为错误?

无用引用: Python functions and their __call__ attribute

最佳答案

您正在创建一个深度嵌套的方法包装器结构。每个方法包装器仍然有对 self 的引用,其中 self 是对父方法包装器的引用,一直回到原始函数:

>>> ret, ret.__call__.__self__
(<function ret at 0x10f17a050>, <function ret at 0x10f17a050>)
>>> ret.__call__, ret.__call__.__call__.__self__
(<method-wrapper '__call__' of function object at 0x10f17a050>, <method-wrapper '__call__' of function object at 0x10f17a050>)

注意方法包装器__self__属性的内存地址是如何指向父对象的。

如果您创建了足够多的这些包装器,您可能会耗尽内存。

Python 为绑定(bind)到一个实例的所有函数创建了这样的包装器。对于带有方法的自定义类也是如此:

>>> class Foo: 
...     def bar(self): return
... 
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x10f1798d0>>
>>> Foo().bar, Foo().bar.__self__
(<bound method Foo.bar of <__main__.Foo object at 0x10f179710>>, <__main__.Foo object at 0x10f179850>)

当通过属性访问访问方法时,方法是根据需要从函数创建的。因为它们持有对 self 的引用,所以只要您持有对它们的引用,它们就会保留在内存中。因此,您的引用链包含 100000 个内存包装器。

关于python - 执行 `func = func.__call__` 时 Python 会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13712672/

相关文章:

python - 为什么 'python3 -m venv myenv' 将旧版本的 pip 安装到 myenv 中,而不是我在系统上任何地方都能找到的任何版本的 pip?

python - 中途结束程序

python - 代码不会停止运行。看起来微不足道,但我无法弄清楚

python - 如何根据列表从 Pandas 数据框中过滤子字符串?

azure - 我应该如何在 Azure 中为我的应用程序实现运行状况检查?

java - 在 Java 中模拟延迟

android - "Don' t 在 Android Studio 中保留“Activity ”选项?

data-binding - Angular2 绑定(bind)属性值

c# - JsonIgnore 属性条件模拟但不是 ShouldSerialize

c# - 为什么属性被延迟实例化?