gpt4 book ai didi

python - 将绑定(bind)方法传递给函数的奇怪行为

转载 作者:太空宇宙 更新时间:2023-11-04 01:02:17 25 4
gpt4 key购买 nike

我相信 func(obj.attr)tmp = obj.attr; func(tmp) 应该是完全不可区分的。但是,下面的代码

class Cls(object):
#@staticmethod
def f(self):
pass

def who(obj):
print(id(obj) % 1000, end=' ')

obj = Cls()

n = 10

for i in range(n):
who(obj.f)

print('\n')

for i in range(n):
tmp = obj.f
who(tmp)

产生

736 736 736 736 736 736 736 736 736 736 

736 216 736 216 736 216 736 216 736 216

我们可以看到第二个 for 循环产生了一个有趣的模式,而第一个则没有。似乎分配绑定(bind)方法会改变绑定(bind)方法本身,但为什么将它传递给函数不会呢?

最佳答案

每次您访问 f 时,Python 都会创建一个 绑定(bind)方法对象(请参阅 Does Python really create all bound method for every new instance?)。

在第一个循环中:

  • 在第一次迭代中:
    • obj.f 创建绑定(bind)方法对象。
    • 打印 id
    • 不再有对绑定(bind)方法对象的引用,因此解释器会立即释放它
  • 在接下来的迭代中:
    • obj.f 创建一个新的绑定(bind)方法对象。 解释器重用在之前的迭代中释放的内存
    • who 打印 happen 匹配前一个 id 的 id
    • 再次释放对象

在第二个循环中:

  • 在第一次迭代
    • obj.f 创建一个新的绑定(bind)方法对象
    • 它被分配给 tmp(因此它现在有一个引用)
    • 打印 id
    • 不执行重新分配tmp 变量使对象保持事件状态
  • 在接下来的迭代中
    • obj.f 创建一个新的绑定(bind)方法对象。 它不能重用旧地址,因为该对象仍然存在。
    • 它被分配给tmp现在 tmp 的旧值没有更多引用,因此被释放。
    • who 打印 id,这是一个新的
    • 同样没有重新分配发生
  • 在接下来的迭代中
    • obj.f 创建一个新的绑定(bind)方法对象。现在旧地址再次可用,解释器决定重新使用它。
    • 它被分配给tmp现在 tmp 的旧值没有更多引用,因此被释放。
    • who 打印 id,这是旧的
    • 同样没有重新分配发生

因此创建了一个在两个地址之间交替的循​​环。

通过使用更多变量,您可以创建更长的周期:

>>> tmp1 = obj.f
>>> tmp2 = tmp3 = tmp4 = tmp5 = None
>>> for i in range(20):
... tmp5 = tmp4
... tmp4 = tmp3
... tmp3 = tmp2
... tmp2 = tmp1
... tmp1 = obj.f
... who(tmp1)
...
864 896 560 280 288 864 896 560 280 288 864 896 560 280 288 864 896 560 280 288

或者,正如 Reblochon Masque 在他的 answer 中提到的那样,使用 del 你可以避免这种行为:

>>> for i in range(20):
... tmp = obj.f
... who(tmp)
... del tmp # forget the name
...
688 688 688 688 688 688 688 688 688 688 688 688 688 688 688 688 688 688 688 688

请注意,这是由于 CPython 的实现细节所致。在 Jython 或其他没有引用计数的 Python 实现中,两个循环的行为可能几乎相同:显示十个不同的 ID。

关于python - 将绑定(bind)方法传递给函数的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32287800/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com