在引用资料的Data Model中,作者花了很多精力解释User-defined methods是如何创建和操作的:(参见http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy并向下滚动)
User-defined method objects may be created when getting an attribute of a class (perhaps via an in- stance of that class), if that attribute is a user-defined function object, an unbound user-defined method object, or a class method object. When the attribute is a user-defined method object, a new method object is only created if the class from which it is being retrieved is the same as, or a derived class of, the class stored in the original method object; otherwise, the original method object is used as it is.
未绑定(bind)的用户定义方法对象和类方法对象有什么区别?
最佳答案
从“用户”的角度来看,Python 中的类方法是一种接收其类作为其第一个参数的方法 - 不同于接收类实例作为其第一个参数的“普通”方法 - 按照惯例是称为 self
。
如果你从一个类中检索一个“普通”方法,而不是从那个类的实例中检索,你会得到一个“未绑定(bind)方法”——即一个对象,它是一个函数的包装器,但它不会自动添加任何一个类本身,也不是任何实例作为调用时的第一个参数。因此,如果您要调用“未绑定(bind)方法”,您必须手动传递其类的实例作为其第一个参数。
如果你手动调用一个类的方法,另一方面,这个类被填入作为你的第一个参数:
>>> class A(object):
... def b(self):
... pass
... @classmethod
... def c(cls):
... pass
...
>>> A.b
<unbound method A.b>
>>> A.c
<bound method type.c of <class '__main__.A'>>
>>> A.c()
>>> A.b()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method b() must be called with A instance as first argument (got nothing instead)
>>>
在幕后发生的事情或多或少是这样的——“新样式类”:
当定义一个类体时,方法只是普通函数——当类体结束时,Python 调用类的元类(通常是内置的 type
)——并传递给它作为参数名称、基类和类主体字典。这个调用产生一个类——在 Python 中是一个对象,它是一个类,因为一切都是对象。
现在,Python 有一些自定义属性访问的巧妙方法 - 所谓的“描述符”。描述符是定义名为 __get__
(或 __set__
或 __del__
但我们在这里不关心这些)的任何对象。当访问 Python 中的类或对象的属性时,返回该属性引用的对象 - 除非它是类属性,并且对象是描述符。在这种情况下,Python 不会返回对象本身,而是对该对象调用 __get__
方法,并返回其结果。例如,内置的 property
只是一个实现了 __set__
、__get__
和 __del__
的类.
现在,检索属性时发生的事情是,其主体上的任何函数(或类方法或未绑定(bind)方法,如数据模型所述)确实具有 __get__
方法,这使得它是一个描述符。基本上,一个描述符在每次访问属性时检索命名为函数的对象,因为它在函数体上定义,围绕该函数创建一个新对象 - 一个在调用时将自动填充第一个参数的对象 - 这是也就是说,一个方法
。
例如:
>>> class B(object):
... def c(self):
... pass
... print c
...
<function c at 0x1927398>
>>> print B.c
<unbound method B.c>
>>> b = B()
>>> b.c
<bound method B.c of <__main__.B object at 0x1930a10>
如果你想检索函数对象,而不转换为方法对象,你可以通过类的__dict__
属性来实现,它不会触发描述符:
>>> B.__dict__["c"]
<function c at 0x1927398>
>>> B.__dict__["c"].__get__
<method-wrapper '__get__' of function object at 0x1927398>
>>> B.__dict__["c"].__get__(b, B)
<bound method B.c of <__main__.B object at 0x1930a10>>
>>> B.__dict__["c"].__get__(None, B)
<unbound method B.c>
至于“类方法”,这些只是不同类型的对象,用内置的 classmethod
显式修饰 - 当它的 __get__
被调用时它返回的对象是原始函数的包装器,它将填充 cls
作为调用时的第一个参数。
关于Python 数据模型文档 : an unbound user-defined method object and a class method object,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9090941/