属性类的函数对象在属性查找时会得到特殊处理吗?

时间:2015-01-25 03:20:33

标签: python python-2.7

我的问题涉及在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对象之外是否还有其他类型的特殊处理?
  • 如果我想阅读更多内容,请记录在哪里?

1 个答案:

答案 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