在开始正文之前,需要了解下Python的绑定方法(bound method)和非绑定方法。

简单做个测试:

定义一个类,类中由实例方法、静态方法和类方法。

  1. class ClassA:
  2.  
  3. def instance_method(self):
  4. print('instance_method', self)
  5.  
  6. @classmethod
  7. def cls_method(cls):
  8. print('cls_method', cls)
  9.  
  10. @staticmethod
  11. def static_method():
  12. print('static_method')

逐个测试,测试的结果在注释说说明。

  1. class_a = ClassA()
  2.  
  3. print('测试实例方法、静态方法、类方法与实例和类的关系')
  4. # 类中的实例方法,与类本身并没有绑定关系
  5. # <function ClassA.instance_method at 0x0000022744592488>
  6. print(ClassA.instance_method)
  7. # 类中的静态方法,与类也没有绑定关系
  8. # <function ClassA.static_method at 0x0000027A5F6D0598>
  9. print(ClassA.static_method)
  10. # 而类中的类方法,是和这个类存在绑定关系的
  11. # <bound method ClassA.cls_method of <class '__main__.ClassA'>>
  12. print(ClassA.cls_method)
  13.  
  14. print('-' * 50)
  15.  
  16. # 实例中的实例方法,与实例存在绑定关系
  17. # 因为当通过一个实例去访问类中的某方法时,会形成绑定关系,将实例作为第一个参数self传入。
  18. # <bound method ClassA.instance_method of <__main__.ClassA object at 0x000001B117D07710>>
  19. print(class_a.instance_method)
  20. # 类方法与实例也存在绑定关系,所以实例可以直接调用类方法
  21. # <bound method ClassA.cls_method of <class '__main__.ClassA'>>
  22. print(class_a.cls_method)
  23. # 静态方法与实例没有绑定关系
  24. # <function ClassA.static_method at 0x0000027D36340620>
  25. print(class_a.static_method)

接着尝试把一个函数,绑定到类或者实例上。

第一种方法,直接将函数赋值给类。

  1. # 创建实例 class_a
  2. class_a = ClassA()
  3.  
  4. # 直接给类属性赋值
  5. ClassA.func_a = func_a
  6.  
  7. # 输出结果,没有绑定关系
  8. # <function func_a at 0x10e41ff28>
  9. print(ClassA.func_a)
  10.  
  11. # 通过实例访问之前赋值的类属性
  12. # 对于赋值之前创建得实例,因为是通过实例访问,所以也会存在绑定关系
  13. # <bound method func_a of <__main__.ClassA object at 0x10e4330b8>>
  14. print(class_a.func_a)

上面这种方法,存在一些局限性。比如把一个函数直接赋值给实例时,无法正常创建绑定关系。

  1. # 把函数赋值给实例
  2. class_a.func_c = func_c
  3. # 没有形成绑定关系
  4. # <function func_c at 0x10e59f1e0>
  5. print(class_a.func_c)

所以,就需要引入MethodType,将一个可调用对象,这里是个函数,绑定到实例或类上,形成绑定关系。

MethodType 会在类内部创建一个链接,指向外部的的可调用对象,在创建实例的同时,这个绑定后的方法也会复制到实例中。MethodType 接受两个参数,第一个是被绑定的可调用对象,第二个是需要绑定到的对象。

  1. class ClassB:
  2. pass
  3.  
  4. class_b = ClassB()
  5.  
  6. class_b.func_a = MethodType(func_a, class_b)
  7.  
  8. print(class_b.func_a)
  9. # <bound method func_a of <__main__.ClassB object at 0x0000021706F6B780>>
  10.  
  11. ClassB.func_b = MethodType(func_b, ClassB)
  12. print(ClassB.func_b)
  13. # <bound method func_b of <class '__main__.ClassB'>>

经过代码测试,成功把函数绑定到了类和实例上。

之前说过,MethodType只是一个链接指向外部可调用对象,而不是把外部可调用对象复制到类内部。

关于这点,可以用一个闭包来验证。

  1. # 闭包
  2. def func_d(a):
  3. def _func_d(self, b):
  4. nonlocal a
  5. a = a + b
  6. print(a)
  7. print(self)
  8. return _func_d
  9.  
  10. # a 初始值为1
  11. test_func_d = func_d(1)

将闭包分别绑定到两个截然不同的类创建出的实例上

  1. class_a.test_func_d = MethodType(test_func_d, class_a)
  2. class_b.test_func_d = MethodType(test_func_d, class_b)

两个不同的实例的test_func_d,实际上是指向同一个函数。

分别调用两个实例的test_func_d方法,得到3、6两个结果。

  1. class_a.test_func_d(2)
  2. #
  3. class_b.test_func_d(3)
  4. #

第一次执行class_a.test_func_d(1)时,闭包中的变量 a 已经由 1 变为 1+2=3,第二次执行class_b.test_func_d(3)时,闭包中的变量 a 已经由 3 变为 3+3=6。

可见两个实例执行的是同一个函数,共享闭包内的变量a,所以说是创建一个链接,指向函数,而不是把函数复制到类内部。

使用MethodType函数将方法绑定到类或实例上的更多相关文章

  1. python中函数和方法区别,以及如何给python类动态绑定方法和属性(涉及types.MethodType()和__slots__)

    网上有很多同义但不同方式的说法,下面的这个说法比较让你容易理解和接受 与类和实例无绑定关系的function都属于函数(function): 与类和实例有绑定关系的function都属于方法(meth ...

  2. day23 面向对象 函数和方法区分

    最近两周内容大概回顾: # 文件操作 # # 模块:random,序列化模块,时间模块,collections,re,os,sys # 模块与包的概念和导入方法 # 写代码的规范 # 正则表达式 # ...

  3. python面向对象( item系列,__enter__ 和__exit__,__call__方法,元类)

    python面向对象进阶(下)   item系列 __slots__方法 __next__ 和 __iter__实现迭代器  析构函数 上下文管理协议 元类一.item系列 把对象操作属性模拟成字典的 ...

  4. issubclass/type/isinstance、函数和方法、反射、callable、特殊成员补充

    一.issubclass/type/isinstance(***) 1.issubclass(参数1, 参数2):检查第一个参数是否是第二个参数的 子子孙孙类,如下示例: class Base(obj ...

  5. Python面向对象-类、实例的绑定属性、绑定方法和__slots__

    绑定属性 从之前的文章中,我们知道python是动态语言——实例可以绑定任意属性. 那如果实例绑定的属性和类的属性名一样的话,会是什么情况呢? >>> class Student(o ...

  6. day26——tyoe元类与object的联系、反射、函数与方法的区别、双下方法

    day26 type元类与object联系 type 获取对象从属于的类 python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类,以及大部分内置类,都是由type元类(构 ...

  7. Oracle数据库中调用Java类开发存储过程、函数的方法

    Oracle数据库中调用Java类开发存储过程.函数的方法 时间:2014年12月24日  浏览:5538次 oracle数据库的开发非常灵活,不仅支持最基本的SQL,而且还提供了独有的PL/SQL, ...

  8. React与ES6(三)ES6类和方法绑定

    React与ES6系列: React与ES6(一)开篇介绍 React和ES6(二)ES6的类和ES7的property initializer React与ES6(三)ES6类和方法绑定 React ...

  9. cocos2dx lua 绑定之二:手动绑定自定义类中的函数

    cococs2dx 3.13.1 + vs2013 + win10 1.首先按照<cocos2dx lua 绑定之一:自动绑定自定义类>绑定Student类 2.在Student类中增加一 ...

随机推荐

  1. OAuth 2.0(网转)

    (一)背景知识 OAuth 2.0很可能是下一代的"用户验证和授权"标准,目前在国内还没有很靠谱的技术资料.为了弘扬"开放精神",让业内的人更容易理解" ...

  2. 简单用数组模拟顺序栈(c++版)适合新手

    **栈是一种操作受限制的线性表,太多官方的话我也不说了,我们都知道栈元素是先进后出的,它有两种存储结构,分别是顺序存储结构和链式存储结构. **今天我先记一下顺序存储结构,后面我会加上链式存储结构的. ...

  3. 【liferay】1、使用alloy-UI发送ajax请求

    1.首先liferay要发送ajax请求,那么就需要在jsp中定义resourceURL <portlet:resourceURL var="workDeal" id=&qu ...

  4. Excel大写和小写转换函数

    Excel中的大写和小写转换函数 (1).转换为所有小写字母:lower函数 (2).转换为所有大写字母:upper函数 (3).转换为首字母大写,其余小写字母:proper函数 三种函数的使用方式. ...

  5. python实现斐波那契数列(Fibonacci sequence)

    使用Python实现斐波那契数列(Fibonacci sequence) 斐波那契数列形如 1,1,2,3,5,8,13,等等.也就是说,下一个值是序列中前两个值之和.写一个函数,给定N,返回第N个斐 ...

  6. eclipse点击空白处自动打开项目

    如图 选择上面的 Link with Editor 即可

  7. python_web----------数据可视化从0到1的过程

    一.数据可视化项目配置 1. django + Echarts 2. 服务器(linux:Ubuntu 17.04 (GNU/Linux 4.10.0-40-generic x86_64)) 3. I ...

  8. Grafana4.2安装

    一.文件准备 1.1 文件名称 grafana-4.2.0-1.x86_64.rpm 1.2 下载地址 https://grafana.com/grafana/download 二.工具准备 2.1 ...

  9. linux根目录扩容

    原来在ucloud上面买了一个服务器,结果根目录上面只有20G,/data挂载点下面有500G,没多久/根目录存储空间用完了,所以要扩展 linux的文件模式分为lvm模式和普通的非lvm模式,云服务 ...

  10. 查看当前支持的shell,echo -e相关转义符,一个简单shell脚本,dos2unix命令把windows格式转为Linux格式

    /etc/shells [root@localhost ~]# more /etc/shells /bin/sh /bin/bash /sbin/nologin /usr/bin/sh /usr/bi ...