使用MethodType函数将方法绑定到类或实例上
在开始正文之前,需要了解下Python的绑定方法(bound method)和非绑定方法。
简单做个测试:
定义一个类,类中由实例方法、静态方法和类方法。
class ClassA:
def instance_method(self):
print('instance_method', self)
@classmethod
def cls_method(cls):
print('cls_method', cls)
@staticmethod
def static_method():
print('static_method')
逐个测试,测试的结果在注释说说明。
class_a = ClassA()
print('测试实例方法、静态方法、类方法与实例和类的关系')
# 类中的实例方法,与类本身并没有绑定关系
# <function ClassA.instance_method at 0x0000022744592488>
print(ClassA.instance_method)
# 类中的静态方法,与类也没有绑定关系
# <function ClassA.static_method at 0x0000027A5F6D0598>
print(ClassA.static_method)
# 而类中的类方法,是和这个类存在绑定关系的
# <bound method ClassA.cls_method of <class '__main__.ClassA'>>
print(ClassA.cls_method)
print('-' * 50)
# 实例中的实例方法,与实例存在绑定关系
# 因为当通过一个实例去访问类中的某方法时,会形成绑定关系,将实例作为第一个参数self传入。
# <bound method ClassA.instance_method of <__main__.ClassA object at 0x000001B117D07710>>
print(class_a.instance_method)
# 类方法与实例也存在绑定关系,所以实例可以直接调用类方法
# <bound method ClassA.cls_method of <class '__main__.ClassA'>>
print(class_a.cls_method)
# 静态方法与实例没有绑定关系
# <function ClassA.static_method at 0x0000027D36340620>
print(class_a.static_method)
接着尝试把一个函数,绑定到类或者实例上。
第一种方法,直接将函数赋值给类。
# 创建实例 class_a
class_a = ClassA() # 直接给类属性赋值
ClassA.func_a = func_a # 输出结果,没有绑定关系
# <function func_a at 0x10e41ff28>
print(ClassA.func_a) # 通过实例访问之前赋值的类属性
# 对于赋值之前创建得实例,因为是通过实例访问,所以也会存在绑定关系
# <bound method func_a of <__main__.ClassA object at 0x10e4330b8>>
print(class_a.func_a)
上面这种方法,存在一些局限性。比如把一个函数直接赋值给实例时,无法正常创建绑定关系。
# 把函数赋值给实例
class_a.func_c = func_c
# 没有形成绑定关系
# <function func_c at 0x10e59f1e0>
print(class_a.func_c)
所以,就需要引入MethodType,将一个可调用对象,这里是个函数,绑定到实例或类上,形成绑定关系。
MethodType 会在类内部创建一个链接,指向外部的的可调用对象,在创建实例的同时,这个绑定后的方法也会复制到实例中。MethodType 接受两个参数,第一个是被绑定的可调用对象,第二个是需要绑定到的对象。
class ClassB:
pass class_b = ClassB() class_b.func_a = MethodType(func_a, class_b) print(class_b.func_a)
# <bound method func_a of <__main__.ClassB object at 0x0000021706F6B780>> ClassB.func_b = MethodType(func_b, ClassB)
print(ClassB.func_b)
# <bound method func_b of <class '__main__.ClassB'>>
经过代码测试,成功把函数绑定到了类和实例上。
之前说过,MethodType只是一个链接指向外部可调用对象,而不是把外部可调用对象复制到类内部。
关于这点,可以用一个闭包来验证。
# 闭包
def func_d(a):
def _func_d(self, b):
nonlocal a
a = a + b
print(a)
print(self)
return _func_d # a 初始值为1
test_func_d = func_d(1)
将闭包分别绑定到两个截然不同的类创建出的实例上
class_a.test_func_d = MethodType(test_func_d, class_a)
class_b.test_func_d = MethodType(test_func_d, class_b)
两个不同的实例的test_func_d,实际上是指向同一个函数。
分别调用两个实例的test_func_d方法,得到3、6两个结果。
class_a.test_func_d(2)
#
class_b.test_func_d(3)
#
第一次执行class_a.test_func_d(1)时,闭包中的变量 a 已经由 1 变为 1+2=3,第二次执行class_b.test_func_d(3)时,闭包中的变量 a 已经由 3 变为 3+3=6。
可见两个实例执行的是同一个函数,共享闭包内的变量a,所以说是创建一个链接,指向函数,而不是把函数复制到类内部。
使用MethodType函数将方法绑定到类或实例上的更多相关文章
- python中函数和方法区别,以及如何给python类动态绑定方法和属性(涉及types.MethodType()和__slots__)
网上有很多同义但不同方式的说法,下面的这个说法比较让你容易理解和接受 与类和实例无绑定关系的function都属于函数(function): 与类和实例有绑定关系的function都属于方法(meth ...
- day23 面向对象 函数和方法区分
最近两周内容大概回顾: # 文件操作 # # 模块:random,序列化模块,时间模块,collections,re,os,sys # 模块与包的概念和导入方法 # 写代码的规范 # 正则表达式 # ...
- python面向对象( item系列,__enter__ 和__exit__,__call__方法,元类)
python面向对象进阶(下) item系列 __slots__方法 __next__ 和 __iter__实现迭代器 析构函数 上下文管理协议 元类一.item系列 把对象操作属性模拟成字典的 ...
- issubclass/type/isinstance、函数和方法、反射、callable、特殊成员补充
一.issubclass/type/isinstance(***) 1.issubclass(参数1, 参数2):检查第一个参数是否是第二个参数的 子子孙孙类,如下示例: class Base(obj ...
- Python面向对象-类、实例的绑定属性、绑定方法和__slots__
绑定属性 从之前的文章中,我们知道python是动态语言——实例可以绑定任意属性. 那如果实例绑定的属性和类的属性名一样的话,会是什么情况呢? >>> class Student(o ...
- day26——tyoe元类与object的联系、反射、函数与方法的区别、双下方法
day26 type元类与object联系 type 获取对象从属于的类 python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类,以及大部分内置类,都是由type元类(构 ...
- Oracle数据库中调用Java类开发存储过程、函数的方法
Oracle数据库中调用Java类开发存储过程.函数的方法 时间:2014年12月24日 浏览:5538次 oracle数据库的开发非常灵活,不仅支持最基本的SQL,而且还提供了独有的PL/SQL, ...
- React与ES6(三)ES6类和方法绑定
React与ES6系列: React与ES6(一)开篇介绍 React和ES6(二)ES6的类和ES7的property initializer React与ES6(三)ES6类和方法绑定 React ...
- cocos2dx lua 绑定之二:手动绑定自定义类中的函数
cococs2dx 3.13.1 + vs2013 + win10 1.首先按照<cocos2dx lua 绑定之一:自动绑定自定义类>绑定Student类 2.在Student类中增加一 ...
随机推荐
- C++反汇编第五讲,认识多重继承,菱形继承的内存结构,以及反汇编中的表现形式.
C++反汇编第五讲,认识多重继承,菱形继承的内存结构,以及反汇编中的表现形式. 目录: 1.多重继承在内存中的表现形式 多重继承在汇编中的表现形式 2.菱形继承 普通的菱形继承 虚继承 汇编中的表现形 ...
- Angular页面加载闪现解决方案 ng-cloak
在做Angular项目时,经常会遇见在浏览器上闪烁表达式({{ express }} ),及模块(div)的闪烁,会闪现/闪烁隐藏的数据,之前用过vue.js,可以通过v-clock解决,同理Angu ...
- 【tyvj P4868】天天和不可描述
http://www.tyvj.cn/p/4868 超级水的题,用递归来模拟,用链表保存这层的内容,每遇到一个左括号就递归一层并合并返回的链表,遇到右括号后返回. 递归进入下一层时传递个参数标记读取新 ...
- javaweb学习总结(五)——Servlet开发(一)(转)
转载自 http://www.cnblogs.com/xdp-gacl/p/3760336.html 一.Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun ...
- Java爬虫——B站弹幕爬取
如何通过B站视频AV号找到弹幕对应的xml文件号 首先爬取视频网页,将对应视频网页源码获得 就可以找到该视频的av号aid=8678034 还有弹幕序号,cid=14295428 弹幕存放位置为 h ...
- ActiveMQ基本详解与总结
MQ简介: MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过写和检索出入列队的针对应用程序的数据(消息)来通信,而无需专用连接来链接它们.消息传 ...
- 10.0.0.55训练赛 Writeup
From LB@10.0.0.55 Misc 0x01 misc100(图片隐写) 首先用binwalk扫了一下,发现没毛病. 然后就搜了一下jpg的文件尾FFD9,如下图,看到了png格式的标志IH ...
- CoordinatorLayout与滚动的处理
本博文专门解说和CoordinatorLayout相关的知识点,这也是Design Support Library中最重要与最难的部分. 概览 CoordinatorLayout实现了多种Materi ...
- hdu 4869 Turn the pokers (思维)
Turn the pokers Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 【npm】如何在Atom中安装emmet和atom-beautify插件?
为了提高编写HTML和CSS的速度,最近尝试着在Atom中安装emmet插件,下面谈谈安装成功的过程 1首先我尝试了网上教程中介绍最多的方法:打开Atom的引导界面(Welcome Guide)中的i ...