如果我有一个
class A:
def foo(self):
pass
计算结果为 True
:
getattr(A, 'foo') is A.foo
但这计算为False
:
a = A()
getattr(a, 'foo') is a.foo
同样
a.foo is a.foo
为什么?
我发现 getattr(a, 'foo')
和 a.foo
都是用
表示的
<bound method A.foo of <__main__.A object at 0x7a2c4de10d50>>)
所以那里没有提示....
至少在 CPython 中,绑定(bind)方法被实现为类 method
的实例。每次请求绑定(bind)函数的值时,都会得到此类的新实例。
x = a.foo
y = a.foo
assert x is not y
id(x) # E.g. 139664144271304
id(y) # E.g. 139664144033992
type(x) # <class 'method'>
type(y) # <class 'method'>
这个类所做的只是存储对实例和未绑定(bind)函数的引用,当您调用该类时,它会使用存储的实例(以及您的其他参数)调用未绑定(bind)函数。
未绑定(bind)函数,如 A.foo
,只是常规的旧函数 - 没有构造代理类的新实例,因此身份如您所愿地工作。
造成这种差异的原因是 a.foo
的语义取决于两个事物,a
的值和A.foo
。为了能够在以后的任何时间点得到这个含义,这两个值都需要被存储。这就是 method
类的作用。
相反,A.foo
的含义仅取决于一个值:A.foo
。因此不需要额外的工作来存储任何东西,而是使用值本身。
您可能会考虑预分配绑定(bind)方法实例的想法,以便 a.foo
始终返回相同的不可变对象(immutable对象) - 但考虑到 Python 的动态特性,它更简单且成本更低每次都构建一个新的,即使它们可能是相同的。