来自Python语言参考Data Models section,在用户定义的方法标题下:
当属性是用户定义的方法对象时,只有在检索它的类与原始方法对象中存储的类相同或派生类时,才会创建新的方法对象;否则,原始方法对象按原样使用。
这句话是什么意思?
答案 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"
此处Bar
是Foo
的子类,未绑定的方法对象重新绑定到类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是属性是函数时的正常情况,3是函数是@classmethod时的正常情况
2是@Pieters提到的情况,其中属性已经是来自其他类的用户定义的方法对象,在这种情况下,除非此对象来自同一个类(或派生类) ),不会创建新的用户定义方法对象,并且将使用旧的用户定义方法