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 对象。 例子,
 class A(object):
def foo(self):
print "haha - " + self.foo.__name__ print (A.__dict__) # abc = A() print (A.foo) # print(A.foo.im_self) # print (abc.foo) # print (abc.foo.im_self,abc.foo.im_func, #
abc.foo.im_class,abc.foo.__name__) abc.foo() #
try:
print A.foo() #
except TypeError as e:
print e 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

Bound Method and Unbound Method - 绑定方法 与 非绑定方法的更多相关文章

  1. Day 5-5 绑定方法与非绑定方法

    绑定方法与非绑定方法: 在类内部定义的绑定方法,分两大类: classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入 ...

  2. Learning-Python【25】:绑定方法与非绑定方法

    类中定义函数分为了两大类,绑定方法与非绑定方法,它们有一些特殊之处: 1.绑定方法特殊之处:绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数自动传入 绑定给对象的方法:这个在面向对象第一篇第六 ...

  3. Python面向对象之封装、property特性、绑定方法与非绑定方法

    一.封装 ''' 1.什么封装 封:属性对外是隐藏的,但对内是开放的(对内是开放的是因为在类定义阶段这种隐藏已经发生改变) 装:申请一个名称空间,往里装入一系列名字/属性 2.为什么要封装 封装数据属 ...

  4. 全面解析python类的绑定方法与非绑定方法

    类中的方法有两类: 绑定方法 非绑定方法 一.绑定方法 1.对象的绑定方法 首先我们明确一个知识点,凡是类中的方法或函数,默认情况下都是绑定给对象使用的.下面,我们通过实例,来慢慢解析绑定方法的应用. ...

  5. Python开发基础-Day21多态与多态性、绑定方法和非绑定方法

    多态与多态性 多态 多态并不是一个新的知识 多态是指一类事物有多种形态,在类里就是指一个抽象类有多个子类,因而多态的概念依赖于继承 举个栗子:动物有多种形态,人.狗.猫.猪等,python的序列数据类 ...

  6. python基础之多态与多态性、绑定方法和非绑定方法

    多态与多态性 多态 多态并不是一个新的知识 多态是指一类事物有多种形态,在类里就是指一个抽象类有多个子类,因而多态的概念依赖于继承 举个栗子:动物有多种形态,人.狗.猫.猪等,python的序列数据类 ...

  7. Python虚拟机类机制之绑定方法和非绑定方法(七)

    Bound Method和Unbound Method 在Python中,当对作为属性的函数进行引用时,会有两种形式,一种称为Bound Method,这种形式是通过类的实例对象进行属性引用,而另一种 ...

  8. Python--多态与多态性、绑定方法与非绑定方法

    多态与多态性 多态 多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承) 1. 序列类型有多种形态:字符串,列表,元组. s='hello' l=[,,] t=('a',' ...

  9. Day7 子类调用父类的方法supper 绑定方法与非绑定方法

    supper:可以利用supper来重用父类的方法,可以不用指名道姓的调用了. class OldboyPeople: school = 'oldboy' def __init__(self,name ...

随机推荐

  1. floj 2264

    2.公路建设(highway.c/cpp/pas) 在滨海市一共有n 个城市,编号依次为1到n,它们之间计划修建m条双向道路,其中修建第i条道路的费用为ci. 海霸王作为滨海市公路建设项目的总工程师, ...

  2. C#实现DataTable转.CSV文件

    将DataTable转换成CSV文件是一种常见的转换形式,主要通过遍历Table的每行,再对每行遍历每列,实现对数据的读取,然后用分隔符分隔Table的每个栏位数据,把读取的字符写入到CSV文件中.这 ...

  3. STM32动态内存分配需要注意的地方

    STM32进行动态内存分配是需要注意动态内存分配大小不要超过.S文件中设置Heap Size大小 如图所示: 0x4000 :可以分配得最大字节是16384bytes 这个地方malloc的大小超过了 ...

  4. 如何实施DevOps

    对于长期在孤立的架构下工作的组织来说,转移到协作式DevOps系统似乎是难以成功的.为了进一步提高效率,必须改变观念,并进行团队文化改变.例如:许多人认为只有自动化工具才能解决DevOps,其实这是不 ...

  5. Linux.vim编辑器显示行号

    显示行号 :set number 取消显示行号:set nonumber

  6. 02.flask-script

    网址:https://pypi.org/project/Flask-Script/ 文档:https://flask-script.readthedocs.io/en/latest/ 1.安装 2.新 ...

  7. 8.JavaSE之变量、常量、作用域

    变量variable: 变量是什么:就是内存中开辟的可以变化的量! Java是一种强类型语言,每个变量都必须声明其类型. Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型,作用域   ...

  8. C#中TripleDES对应Java中的DESede即大家说的3DES,附C#及Java加解密结果一致的控制台程序例子

    直接上代码了. Java控制台代码: package Test; import java.security.Key; import javax.crypto.Cipher; import javax. ...

  9. php---> xhprof安装及使用

    xhprof 简介 xhprof是一款网站的性能工具 安装(lnmp) php --ri xhprof #检查php是否有这个扩展 cd xhprof-0.9.4/xhprof-0.9.4/exten ...

  10. Mondriaan's Dream 轮廓线DP 状压

    Mondriaan's Dream 题目链接 Problem Description Squares and rectangles fascinated the famous Dutch painte ...