我的问题涉及在function
对象在属性查找时如何转换为绑定或未绑定instancemethod
。具体来说,我对行为表示感兴趣,即function
对象尽管是描述符,但实际上并没有这样对待。对于以下内容,请假设Python 2。
Python中用户定义的函数对象实现了描述符接口。也就是说,函数对象具有__get__
方法:
>>> def bar(): return 42
>>> bar.__get__
<method-wrapper '__get__' of function object at 0x104b2eaa0>
我的理解是method-wrapper
是一个特定于cPython的类型,它创建一个将bar
与类或实例相关联的未绑定或绑定方法对象:
>>> class Foo(object): pass
>>> bar.__get__(None, Foo)
<unbound method Foo.bar>
现在,写
>>> Foo.bar = bar
具有将bar
函数对象添加到Foo.__dict__
的效果。由于bar
是描述符,因此编写
>>> Foo.bar
所调用
>>> Foo.__dict__["bar"].__get__(None, Foo)
<unbound method Foo.bar>
基本上,我的问题是这最后的说法是否属实。 Foo.bar
真的致电Foo.__dict__["bar"].get__(None, Foo)
吗?以下似乎是相反的证据:我们可以用明确不 a __get__
的东西替换bar
的{{1}}属性,并且它不会t改变函数的绑定方式。例如,
method-wrapper
所以>>> def bar(): return 42
>>> bar.__get__ = "This won't bind bar to anything"
>>> class Foo(object): pass
>>> Foo.bar = bar
>>> Foo.bar
<unbound method Foo.bar>
>>> Foo.__dict__["bar"].__get__
"This won't bind bar to anything"
尽管是一个描述符,似乎并没有像一个人那样被使用。
这是我猜测当写一个bar
时实际发生的事情:解释器在Foo.bar
中找到bar
,一个函数对象。它不是像任何其他描述符一样调用Foo.__dict__
,而是继续仅由bar.__get__
对象调用的特殊行为:它会自动将function
包装在未绑定或绑定的方法对象中,具体取决于根据需要。
我的问题是这些:
function
对象转换为方法对象吗?function
对象之外是否还有其他类型的特殊处理?答案 0 :(得分:2)
它会调用__get__
。但是,与所有特殊方法一样,__get__
在类上查找,而不是实例,如here所述。换句话说,它不会调用Foo.__dict__["bar"].__get__(None, Foo)
;它调用Foo.__dict__["bar"].__class__.__get__(Foo.__dict__["bar"], None, Foo)
。因此,在单个函数上设置__get__
无效。
如果您同样尝试在实例上设置__get__
,则不仅可以使用函数,而且可以使用普通的用户定义描述符来查看相同的行为:
class Descriptor(object):
def __get__(self, obj, cls):
print("Getting")
return 42
desc = Descriptor()
def fakeGet(self, obj, cls):
print("This will not be called")
return 88
class Foo(object):
pass
Foo.bar = desc
>>> Foo.bar
Getting
42
# setting a new __get__ directly on the descriptor instance won't work
>>> desc.__get__ = fakeGet
>>> Foo.bar
Getting
42