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 相关文章推荐
简单理解Python中基于生成器的状态机
Apr 13 Python
Python3实现并发检验代理池地址的方法
Sep 18 Python
python用Pygal如何生成漂亮的SVG图像详解
Feb 10 Python
Python制作豆瓣图片的爬虫
Dec 28 Python
Python 字符串与二进制串的相互转换示例
Jul 23 Python
浅谈Python中的全局锁(GIL)问题
Jan 11 Python
python定时按日期备份MySQL数据并压缩
Apr 19 Python
pyqt弹出新对话框,以及关闭对话框获取数据的实例
Jun 18 Python
Python对Tornado请求与响应的数据处理
Feb 12 Python
在pycharm中实现删除bookmark
Feb 14 Python
python小技巧——将变量保存在本地及读取
Nov 13 Python
C++和python实现阿姆斯特朗数字查找实例代码
Dec 07 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
星际争霸, 教主第一视角, ZvT经典龙蛇演义
2020/03/02 星际争霸
php&amp;mysql 日期操作小记
2012/02/27 PHP
PHP批量生成静态HTML的简单原理和方法
2014/04/20 PHP
Zend Framework入门教程之Zend_Config组件用法详解
2016/12/09 PHP
laravel框架实现后台登录、退出功能示例
2019/10/31 PHP
laravel 框架结合关联查询 when()用法分析
2019/11/22 PHP
jquery实现的超出屏幕时把固定层变为定位层的代码
2010/02/23 Javascript
jquery focus(fn),blur(fn)方法实例代码
2011/12/16 Javascript
jquery $.ajax相关用法分享
2012/03/16 Javascript
jQuery实现的网页左侧在线客服效果代码
2015/10/23 Javascript
基于Node.js实现nodemailer邮件发送
2016/01/26 Javascript
bootstrap基本配置_动力节点Java学院整理
2017/07/14 Javascript
Babel 入门教程学习笔记
2018/06/13 Javascript
angular6.0开发教程之如何安装angular6.0框架
2018/06/29 Javascript
webpack 开发和生产并行设置的方法
2018/11/08 Javascript
记一次用vue做的活动页的方法步骤
2019/04/11 Javascript
详解 微信小程序开发框架(MINA)
2019/05/17 Javascript
JavaScript实现省市区三级联动
2020/02/13 Javascript
JavaScript浅层克隆与深度克隆示例详解
2020/09/01 Javascript
[00:47]DOTA2荣耀之路6:玩不了啦!
2018/05/30 DOTA
多线程爬虫批量下载pcgame图片url 保存为xml的实现代码
2013/01/17 Python
Python中用format函数格式化字符串的用法
2015/04/08 Python
详解如何设置Python环境变量?
2019/05/13 Python
python实现的接收邮件功能示例【基于网易POP3服务器】
2019/09/11 Python
Pytorch 实现focal_loss 多类别和二分类示例
2020/01/14 Python
python topk()函数求最大和最小值实例
2020/04/02 Python
Python发起请求提示UnicodeEncodeError错误代码解决方法
2020/04/21 Python
Python3以GitHub为例来实现模拟登录和爬取的实例讲解
2020/07/30 Python
Python爬虫防封ip的一些技巧
2020/08/06 Python
俄罗斯外国汽车和国产汽车配件网上商店:Движком
2020/04/19 全球购物
iostream与iostream.h的区别
2015/01/16 面试题
励志广播稿300字(5篇)
2014/09/15 职场文书
停水通知
2015/04/16 职场文书
css3 利用transform-origin 实现圆点分布在大圆上布局及旋转特效
2021/04/29 HTML / CSS
Spring Boot DevTools 全局配置学习指南
2022/03/31 Java/Android
Go语言的协程上下文的几个方法和用法
2022/04/11 Golang