Python类的动态修改的实例方法


Posted in Python onMarch 24, 2017

Python类的动态修改的实例方法

相信很多朋友在编程的时候都会想修改一下已经写好的程序行为代码,而最常见的方式就是通过子类来重写父类的一些不满足需求的方法。比如说下面这个例子。

class Dog:
  def bark(self):
    print 'Woof!'
 
class Husky(Dog):
  def bark(self)
    print 'Howl!'

我们可以用上述方式来修改我们自己写的代码,但是我们应该怎么修改第三方代码呢?当然,我们也可以自己编写一个子类,调用子类的实例对象来实现修改,但是这样可能会引入其他一系列问题。所以我们得想个办法用我们自己的方法替换掉原来的对象方法,这就是本文接下来要介绍的“打补丁”的方式。

给类打补丁

如果我们想新增或是修改对象的方法的话,最简单的方式莫过于给类打个补丁了。结合上面的例子,如果我们想给我们自己的 Dog 类写一个新的 howl 方法的话,我们可以定义一个新的 howl 函数,像下面的代码一样把它添加到我们的类中:

def newbark(self):
  print 'Wrooof!'
 
def howl(self):
  print 'Howl!'
 
# Replace an existing method
Dog.bark = newbark
 
# Add a new method
Dog.howl = howl

很简单吧?但是这里有几个问题需要我们注意。首先,被修改的类的所有实例中的方法都会被更新,所以更新后的方法不仅仅存在于新创建的对象中,之前创建的所有对象都会拥有更新之后的方法,除非只是新增而不是覆盖掉原来的方法。第二,你修改或者新增的方法应当是与对象绑定的,所以方法的第一个参数应当是被调用的对象(在这里就是类的实例self)。

给类实例打补丁

单个对象也可以在不影响这个类的其他实例的情况下打补丁。但是还是有点小技巧的哦!先让我们看看下面这个例子。

def herd(self, sheep):
  self.run()
  self.bark()
  self.run()
 
border_collie = Dog()
border_collie.herd = herd

然后我们再试试调用新定义的方法:

border_collie.herd(sheep)
 
TypeError: herd() takes exactly 2 arguments (1 given)
The problem with the previous code is that the herd is not a bound method, just take a look at the following code:
 
print border_collie.herd
 
<function herd at 0xf9c5f0>

出错啦!引发错误的原因就是被调用的对象并没有作为第一个参数传给我们写的函数。当然我们可以自己把参数传进去,但是在这个替换类方法的场景下并不奏效。解决这个问题的正确方案是用 type 这个模块里的 MethodType 函数,我们可以看看下面的示例代码:

import types
 
border_collie = Dog()
border_collie.herd = types.MethodType(herd, border_collie)
 
print border_collie.herd
<bound method ?.herd of <__main__.Dog instance at 0x23c9518>>
 
border_collie.herd(sheep)

现在我们的方法已经和实例绑定了,大功告成!

总结

运行中替换或者添加方法是非常有用的,比如说在单元测试中,有些负责和外界服务通信的函数就需要替换掉,方便测试。这个技巧不仅很常用,而且在你最终决定要修改代码之前还可以保持代码的可维护性,是一个非常重要的技巧。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Python 相关文章推荐
sqlalchemy对象转dict的示例
Apr 22 Python
Python进阶学习之特殊方法实例详析
Dec 01 Python
Tensorflow环境搭建的方法步骤
Feb 07 Python
基于python神经卷积网络的人脸识别
May 24 Python
python入门:这篇文章带你直接学会python
Sep 14 Python
windows7 32、64位下python爬虫框架scrapy环境的搭建方法
Nov 29 Python
PyQt5实现简单数据标注工具
Mar 18 Python
python实现动态数组的示例代码
Jul 15 Python
Python配置文件处理的方法教程
Aug 29 Python
Python编程快速上手——正则表达式查找功能案例分析
Feb 28 Python
Python 列表中的修改、添加和删除元素的实现
Jun 11 Python
python logging模块的使用详解
Oct 23 Python
Python操作Excel之xlsx文件
Mar 24 #Python
解决uWSGI的编码问题详解
Mar 24 #Python
Python中动态创建类实例的方法
Mar 24 #Python
python3中set(集合)的语法总结分享
Mar 24 #Python
Python Socket编程详细介绍
Mar 23 #Python
python3中int(整型)的使用教程
Mar 23 #Python
python利用Guetzli批量压缩图片
Mar 23 #Python
You might like
用PHP函数解决SQL injection
2006/12/09 PHP
php的access操作类
2008/04/09 PHP
在PHP中养成7个面向对象的好习惯
2010/01/28 PHP
如何在旧的PHP系统中使用PHP 5.3之后的库
2015/12/02 PHP
golang实现php里的serialize()和unserialize()序列和反序列方法详解
2018/10/30 PHP
PHP延迟静态绑定使用方法实例解析
2020/09/05 PHP
让getElementsByName适应IE和firefox的方法
2007/09/24 Javascript
javascript中的一些注意事项 更新中
2010/12/06 Javascript
js+css使DIV始终居于屏幕中间 左下 左上 右上 右下的代码集合
2011/03/10 Javascript
JS 实现导航栏悬停效果
2013/09/23 Javascript
JavaScript中对象介绍
2014/12/31 Javascript
JS获取下拉框显示值和判断单选按钮的方法
2015/07/09 Javascript
JS实现可点击展开与关闭的左侧广告代码
2015/09/02 Javascript
Jquery on方法绑定事件后执行多次的解决方法
2016/06/02 Javascript
jQuery实现移动端Tab选项卡效果
2017/03/15 Javascript
socket.io学习教程之深入学习篇(三)
2017/04/29 Javascript
angular使用post、get向后台传参的问题实例
2017/05/27 Javascript
BootStrap selectpicker后台动态绑定数据的方法
2017/07/28 Javascript
vue.js input框之间赋值方法
2018/08/24 Javascript
浅谈Layui的eleTree树式选择器使用方法
2019/09/25 Javascript
Vue 使用beforeEach实现登录状态检查功能
2019/10/31 Javascript
javascript运行机制之执行顺序理解
2020/08/03 Javascript
JavaScript实现4位随机验证码的生成
2021/01/28 Javascript
[01:33:14]LGD vs VP Supermajor 败者组决赛 BO3 第二场 6.10
2018/07/04 DOTA
浅谈Python基础之I/O模型
2017/05/11 Python
老生常谈Python序列化和反序列化
2017/06/28 Python
Python3.4实现远程控制电脑开关机
2018/02/22 Python
对Python3 * 和 ** 运算符详解
2019/02/16 Python
Python3爬虫之自动查询天气并实现语音播报
2019/02/21 Python
ORM Django 终端打印 SQL 语句实现解析
2019/08/09 Python
Python随机数函数代码实例解析
2020/02/09 Python
Python+Django+MySQL实现基于Web版的增删改查的示例代码
2020/05/13 Python
CSS3属性选择符介绍
2008/10/17 HTML / CSS
在求职信中如何凸显个人优势
2013/10/30 职场文书
2016年安全生产先进个人事迹材料
2016/02/29 职场文书
方法汇总:Python 安装第三方库常用
2022/04/26 Python