zoukankan      html  css  js  c++  java
  • Bound Method and Unbound Method

    
    
    Bound Method and Unbound Method

    通常有两种方法对类的方法(instance.method)/属性(class.attribute)进行引用, 一种称做 Bound Method,
       即通过类的类的实例对象进行引用(instance.foo)。引用区别于调用, 引用为 instance.foo 返回的是方法对象
       (PyFunctionObject/PyMethodObject); 而调用返回的是方法的运行结果。另一种引用形式叫做 Unboud Method,
       是直接通过类进行属性引用, 即 class.foo 的形式进行引用。

    在 python 中, Bound Method 和 Unbound Method 的本质区别在于 是否存在类的 instance 对象绑定到
       PyFunctionObject 中(这里用 '中' 是想说明 PyFunctionObject 是一个结构体,我把它想象成一个容器的形象)。
    因此, 在对 Unbound Method 进行调用的时候必须显式地传一个实例对象, 比如 class.UnboundMethod(instance),
       所以说在类中所定义函数的第一个位置参数 self 代表是调用该函数的实例。 然而, 对 python 虚拟机来说, 无论是对
       Bound Method 还是对 Unbound Method 进行调用, 其中本质上是一样的,都是调用带位置参数的普通函数。
    其中的区别在于, 当调用 Bound Method 的时候,虚拟机自主完成了 instance 和 PyFunctionObject 的绑定;
       而调用 Unbound Method 的时候虚拟机无法做绑定的动过,因而调用 Unbound Method 的时候需要显式地传入所属类的 instance.
    对于通过 Bound Method 调用成员函数来说,每一次函数调用都会触发一次绑定过程。原因在于每次进行引用的时候都会重新获得
       PyFunctionObject(description),进而新的 PyMethodObject 对象。

    例子,
     1 class A(object):
     2     def foo(self):
     3         print "haha - " + self.foo.__name__
     4 
     5 print (A.__dict__)                                                      #1
     6 
     7 abc = A()
     8 
     9 print (A.foo)                                                           #2
    10 
    11 print(A.foo.im_self)                                                    #3
    12 
    13 print (abc.foo)                                                         #4
    14 
    15 print (abc.foo.im_self,abc.foo.im_func,                                 #5
    16        abc.foo.im_class,abc.foo.__name__)
    17 
    18 abc.foo()                                                               #6
    19 try:
    20     print A.foo()                                                       #7
    21 except TypeError as e:                            
    22     print e
    23 
    24 A.foo(abc)                                                              #7

    通过 dis 模块获取到示例代码的部分字节码,
    31 LOAD_NAME 1 (A)
    34 LOAD_ATTR 3 (foo)
    37 PRINT_ITEM

       其中关键在 '34 LOAD_ATTR' 指令一行, LOAD_ATTR 指令最终会调用 type_getattro。
       而 type_getattro 会在 class A 对象的 tp_dict (__dict__ 属性) 中找到 function foo 对应的 PyFunctionObject.
       因为 PyFunctionObject 是一个 descriptor,所以它会调用其 __get__ 函数. 最终,虽然 A.foo(class.foo, Unbound Method)
       也得到了一个 PyMethodObject, 但是其中 im_self 属性却是 None.

    示例代码的打印输出,
        Output,
        {... 'foo': <function foo at 0x00000000033A2D68>, '__weakref__': <attribute '__weakref__' of 'A' objects>, ...}  
      #1 type_getattro 会在 class A 对象的 tp_dict (__dict__ 属性) 中找到 function foo 对应的 PyFunctionObject.

        <unbound method A.foo> #2 通过类的引用(class.foo) 为 Unbound Method

        None #3 虽然 A.foo(class.foo, Unbound Method)也得到了一个 PyMethodObject, 但是其中 im_self 属性却是 None.

        <bound method A.foo of <__main__.A object at 0x000000000330AE80>> #4 通过实例的引用(instance.foo) 为 Bound Method

        (<__main__.A object at 0x000000000330AE80>, <function foo at 0x00000000033A2D68>, <class '__main__.A'>, 'foo')
          #5 abc.foo(instance.foo, Bound Method)得到的 PyMethodObject 中 im_self 和 im_func 属性分别是 __main__.A 实例对象 和 foo 函数对象.

        haha - foo #6 通过实例调用 foo

        unbound method foo() must be called with A instance as first argument (got nothing instead) #7 Unbound Method 的调用需要显式地传入实例 instance 对象.
        haha - foo


  • 相关阅读:
    构建安全的Xml Web Service系列之如何察看SoapMessage
    web2.0盈利模式
    Asp.Net ajax v1.0莫名出现"Sys未定义"的原因
    北京街头发生一幕~让人深思!!!
    算法函数:得到一个字符串中的最大长度的数字
    手把手教你如何扩展GridView之自动排序篇
    手把手教你如何扩展GridView之自带Excel和Word导出
    nhibernate学习之集合组合依赖
    递归算法学习系列一(分而治之策略)
    手把手教你如何扩展GridView之自带分页
  • 原文地址:https://www.cnblogs.com/zzyzz/p/7489637.html
Copyright © 2011-2022 走看看