我想知道为什么method
存在两个副本,一个用于实例对象,另一个用于类对象,为什么它是这样设计的
class Bar():
def method(self):
pass
@classmethod
def clsmethod(cls):
pass
b1 = Bar()
b2 = Bar()
print(Bar.method,id(Bar.method))
print(b1.method,id(b1.method))
print(b2.method,id(b2.method))
print(Bar.clsmethod,id(Bar.clsmethod))
print(b1.clsmethod,id(b1.clsmethod))
print(b2.clsmethod,id(b2.clsmethod))
此设计基于descriptors,特别是non-data descriptors。通过定义
__get__
方法,每个函数恰好都是非数据描述符:当代码中有一个表达式
x.y
时,这意味着在对象x
上查找属性y
。具体的规则是explained here,其中一个涉及y
是存储在x
类(或任何子类)上的(非)数据描述符。以下是一个例子:这里
Foo.test
在类Foo
上查找名称test
。结果是在全局命名空间中定义的函数:但是,正如我们上面所看到的,每个函数也是一个描述符,因此如果在
Foo
的实例上查找test
,它将调用描述符的__get__
方法来计算结果:我们可以通过手动调用
Foo.test.__get__
获得类似的结果:这种机制确保实例(通常通过
self
表示)作为第一个参数传递给实例方法。描述符返回一个绑定方法(绑定到执行查找的实例),而不是原始函数。此绑定方法在调用时将实例作为第一个参数插入。每次执行Foo.test
操作时,都会返回一个新的绑定方法对象,因此它们的id
不同使用} 的情况类似。唯一的区别是,对于实例
classmethod
的情况与调用^{object.__getattribute__
被调用,而对于类type.__getattribute__
优先相关问题 更多 >
编程相关推荐