不确定Python文档中有关用户定义的方法对象的内容

时间:2016-04-05 08:00:38

标签: python class methods

来自Python语言参考Data Models section,在用户定义的方法标题下:

  

当属性是用户定义的方法对象时,只有在检索它的类与原始方法对象中存储的类相同或派生类时,才会创建新的方法对象;否则,原始方法对象按原样使用。

这句话是什么意思?

2 个答案:

答案 0 :(得分:2)

当您在类或实例上查找名称时,

Python 2 绑定功能,请参阅descriptor protocol。在类上执行此操作时,结果是未绑定方法

>>> class Foo(object):
...     def bar(self):
...         return 'Method bound to {!r}, from class Foo'.format(self)
...     def __repr__(self):
...         return '<Instance of type {!r}>'.format(type(self))
...
>>> Foo.bar
<unbound method Foo.bar>

此对象包含对原始类的引用,以及原始函数对象:

>>> Foo.bar.im_class
<class '__main__.Foo'>
>>> Foo.bar.__func__  # new name, old name im_self still works too
<function bar at 0x105d2a9b0>

这里的术语未绑定指的是它未绑定到实例的事实;但 绑定到该类。

该文本告诉您,当您将这些未绑定的方法对象粘贴到另一个类时,它会将这些对象视为与函数相同。因此,如果您这样做,方法对象将回弹到新类;原始函数对象被引用并反弹到新类:

>>> class Bar(Foo):
...     bar = Foo.bar   # an unbound method from the Foo class!
...
>>> Bar.bar
<unbound method Bar.bar>
>>> Bar.bar.im_class
<class '__main__.Bar'>
>>> Bar().bar()  # it'll work like any other method
"Method bound to <Instance of type <class '__main__.Bar'>>, from class Foo"

此处BarFoo的子类,未绑定的方法对象重新绑定到类Bar

但是,如果您将未绑定的方法粘贴到不属于Foo的子类的其他类上,则该文本指出此不会

>>> class Baz(object):   # not derived from Foo
...     bar = Foo.bar
...
>>> Baz.bar
<unbound method Foo.bar>
>>> Baz.bar.im_class
<class '__main__.Foo'>
>>> Baz().bar
<unbound method Foo.bar>
>>> Baz().bar()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)

您必须通过Foo.bar.__func__访问原始功能,或通过访问课程__dict__完全规避描述符协议(因此请使用Foo.__class__['bar'])以避免此问题共

参考文档中的文字相当令人困惑,因为这个并不适用于完全绑定的方法,即使它意味着它应该;即使在课堂上使用它们也永远不会重新绑定:

>>> class Spam(object):
...     bar = Foo().bar  # *bound* method, taken from an instance of Foo
...
>>> Spam.bar
<bound method Foo.bar of <Instance of type <class '__main__.Foo'>>>
>>> Spam().bar
<bound method Foo.bar of <Instance of type <class '__main__.Foo'>>>
>>> Spam().bar()
"Method bound to <Instance of type <class '__main__.Foo'>>, from class Foo"

Python 3完全摆脱了未绑定的方法;从类对象中检索函数会为您提供原始函数对象。上述限制已完全放弃。

答案 1 :(得分:0)

感谢@Pieters的精彩回答,并且一次又一次地阅读文档和实验。我终于明白了医生想说的话:

用户定义的方法对象是一个带

的对象
  1. 一个班级(im_class)
  2. 一个类实例(im_self)
  3. a callable(im_func)
  4. 每当我们尝试获取类的属性时,如果属性如下,则将创建用户定义方法对象

    1. 用户定义的函数对象
    2. 未绑定的用户定义方法对象
    3. 类方法对象
    4. 1是属性是函数时的正常情况,3是函数是@classmethod时的正常情况

      2是@Pieters提到的情况,其中属性已经是来自其他类的用户定义的方法对象,在这种情况下,除非此对象来自同一个类(或派生类) ),不会创建新的用户定义方法对象,并且将使用旧的用户定义方法