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

Det*_*ant 3 python oop methods object python-datamodel

在参考文献的数据模型中,作者花了很多精力来解释如何创建和操作用户定义的方法 :(参见http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy和roll下)

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

那么未绑定的用户定义的方法对象类方法对象之间的区别是什么?

jsb*_*eno 6

从"用户"的角度来看,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)
>>> 
Run Code Online (Sandbox Code Playgroud)

在幕后,或多或少会像这样 - "新风格":

当定义一个类体时,这些方法只是普通的函数 - 当类体结束时,Python调用类的元类(通常是内置type函数) - 并将其作为参数传递给它,名称,基类和类体字典.这个调用产生一个类 - 在Python中,它是一个类的对象,因为一切都是对象.

现在,Python有一些很好的自定义属性访问方式 - 所谓的"描述符".一个描述符是定义一个名为方法的对象__get__(或__set____del__,但我们不关心那些在这里).当在Python中访问类或对象的属性时,将返回该属性引用的对象 - 除非它是类属性,并且该对象是描述符.在这种情况下,Python不是返回对象本身,而是调用该__get__对象上的 方法,而是返回其结果.例如,property内置函数只是一个实现这两者的类__set__,__get__并且__del__适当时.

现在,在检索属性时会发生什么,它的主体上的任何函数(或类方法或未绑定方法,如数据模型所述)都有一个__get__方法,这使得它成为描述符.基本上,一个描述符在每个属性访问时检索被命名为函数体上定义的函数的对象,在该函数周围创建一个新对象 - 一个被调用的对象将自动填充第一个参数 - 这是说,a 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>
Run Code Online (Sandbox Code Playgroud)

如果要在不转换为方法对象的情况下检索函数对象,可以通过类的__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>
Run Code Online (Sandbox Code Playgroud)

至于"类方法",这些只是不同类型的对象,它们使用内置显式修饰classmethod- 调用它时返回的对象__get__是原始函数的包装器,它将填充cls作为调用时的第一个参数.