Python数据模型文档:一个未绑定的用户定义方法对象和一个类方法对象

Posted

技术标签:

【中文标题】Python数据模型文档:一个未绑定的用户定义方法对象和一个类方法对象【英文标题】:Python Data Model Document : an unbound user-defined method object and a class method object 【发布时间】:2012-02-23 20:16:47 【问题描述】:

在参考资料的Data Model中,作者花了很多功夫解释用户定义的方法是如何创建和操作的:(见http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy并下滚)

获取属性时可能会创建用户定义的方法对象 一个类(可能通过该类的一个实例),如果 属性是一个用户定义的函数对象,一个未绑定的用户定义 方法对象,或类方法对象。 当属性是 用户定义的方法对象,一个新的方法对象只有在 从中检索它的类与或派生类相同 class of,存储在原始方法对象中的类;否则, 原始方法对象按原样使用。

那么未绑定的用户自定义方法对象类方法对象有什么区别呢?

【问题讨论】:

【参考方案1】:

从“用户”的角度来看,Python 中的类方法是接收其类作为其第一个参数的方法 - 与接收类实例作为其第一个参数的“普通”方法不同 - 按照惯例,叫self

如果您从一个类中检索“普通”方法,而不是从该类的实例中检索,您将获得一个“未绑定方法” - 即一个对象,它是一个函数的包装器,但不会自动添加类本身,也没有任何实例作为调用时的第一个参数。因此,如果要调用“未绑定方法”,则必须手动将其类的实例作为其第一个参数传递。

如果你手动调用一个类的方法,另一方面,这个类作为你的第一个参数被填写:

>>> 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__ 的类。

现在,当检索到属性时会发生什么,它的主体上的任何函数(或类方法或未绑定方法,如数据模型所述)确实有一个 __get__ 方法,这使它成为一个描述符。基本上,一个描述符在每个属性访问以检索在函数体上定义的命名为函数的对象,围绕该函数创建一个新对象 - 一个在调用时将自动填充第一个参数的对象 - 这是也就是说,method

例如:

>>> 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 作为调用的第一个参数。

【讨论】:

所以绑定/未绑定的用户定义方法是“实例的方法”,而类方法是“类的方法,对吧? 换句话说,如果你尝试直接从类中调用未绑定的方法,你会得到异常,并且为了调用这个方法,你必须首先创建对象,然后调用方法“from”对象。如果你想直接从类中调用方法,你可以使用装饰器@staticmethod @Denis 那么,当得到一个用@classmethod装饰的方法的属性时,我们可以说它是类的绑定方法吗? 是的 - 它是一个类方法,绑定到类。

以上是关于Python数据模型文档:一个未绑定的用户定义方法对象和一个类方法对象的主要内容,如果未能解决你的问题,请参考以下文章

术语:用户定义的函数对象属性?

在 Python 3 中获取未绑定方法对象的定义类

Python 数据模型:再次与类方法混淆

来自 JQuery 填充字段的值未绑定到 MVC 模型

Python:绑定一个未绑定的方法?

自定义用户控件的 DependencyProperty 绑定未在更改时更新