我发现以下示例有点令人惊讶:
>>> class Foo:
def blah(self):
pass
>>> f = Foo()
>>> def bar(self):
pass
>>> Foo.bar = bar
>>> f.bar
<bound method Foo.bar of <__main__.Foo object at 0x02D18FB0>>
Run Code Online (Sandbox Code Playgroud)
我希望绑定方法与每个特定实例相关联,并在构造时放入其中.似乎合乎逻辑的是,绑定方法必须对每个实例都不同,以便它知道将哪个实例传递给底层函数 - 实际上:
>>> g = Foo()
>>> g.blah is f.blah
False
Run Code Online (Sandbox Code Playgroud)
但是我对这个过程的理解显然是有缺陷的,因为我不希望将一个函数分配给一个类属性会把它放在那时已经创建的实例中.
所以,我的问题是双重的 -
kin*_*all 11
你想打扰你的想法,试试这个:
f.blah is f.blah
Run Code Online (Sandbox Code Playgroud)
没错,每次访问它时,实例方法包装器都是不同的.
实际上,实例方法是描述符.换句话说,f.blah实际上是:
Foo.blah.__get__(f, type(f))
Run Code Online (Sandbox Code Playgroud)
方法实际上并不存储在实例上; 它们存储在类中,并且动态生成方法包装器以将方法绑定到实例.
实例不"包含"该方法.查找过程在您访问时动态发生foo.bar.它检查实例是否具有该名称的属性.因为它没有,它会在类上查找,然后它会找到该类当时具有的任何属性.请注意,方法在这方面并不特别.如果你设置Foo.bar = 2,你会看到相同的效果; 之后,foo.bar将评估为2.
该语言保证的是,属性查找以这种方式进行:首先是实例,然后是在实例上找不到属性的类.(对于通过运算符重载等隐式调用的特殊方法,查找规则是不同的.)
只有直接为实例分配属性时,才会屏蔽class属性.
>>> foo = Foo()
>>> foo.bar
Traceback (most recent call last):
File "<pyshell#79>", line 1, in <module>
foo.bar
AttributeError: 'Foo' object has no attribute 'bar'
>>> foo.bar = 2
>>> Foo.bar = 88
>>> foo.bar
2
Run Code Online (Sandbox Code Playgroud)
以上所有内容都与绑定/未绑定方法分开.Python中的类机制使用描述符协议,以便在访问时foo.bar,动态创建新的绑定方法实例.这就是为什么你在不同的对象上看到不同的绑定方法实例.但请注意,这些绑定方法基本上依赖于您在类中编写的方法所定义的相同代码对象:
>>> foo = Foo()
>>> foo2 = Foo()
>>> foo.blah.im_func.__code__ is foo2.blah.im_func.__code__
True
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1604 次 |
| 最近记录: |