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中的random()方法的使用介绍
May 15 Python
在Python中的Django框架中进行字符串翻译
Jul 27 Python
Python编程使用NLTK进行自然语言处理详解
Nov 16 Python
python+django加载静态网页模板解析
Dec 12 Python
python搭建服务器实现两个Android客户端间收发消息
Apr 12 Python
Python面向对象程序设计中类的定义、实例化、封装及私有变量/方法详解
Feb 28 Python
Python爬取新型冠状病毒“谣言”新闻进行数据分析
Feb 16 Python
python tqdm 实现滚动条不上下滚动代码(保持一行内滚动)
Feb 19 Python
Jupyter Notebook 实现正常显示中文和负号
Apr 24 Python
简述 Python 的类和对象
Aug 21 Python
python使用selenium爬虫知乎的方法示例
Oct 28 Python
Python并发爬虫常用实现方法解析
Nov 19 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 截取字符串并以零补齐str_pad() 函数
2011/05/07 PHP
thinkphp 一个页面使用2次分页的实现方法
2013/07/15 PHP
如何使用PHP批量去除文件UTF8 BOM信息
2013/08/05 PHP
PHP魔术引号所带来的安全问题分析
2014/07/15 PHP
php返回相对时间(如:20分钟前,3天前)的方法
2015/04/14 PHP
微信获取用户地理位置信息的原理与步骤
2015/11/12 PHP
php中static和const关键字用法分析
2016/12/07 PHP
PHP+Oracle本地开发环境搭建方法详解
2019/04/01 PHP
js innerHTML 的一些问题的解决方法
2008/06/22 Javascript
jquery tab插件制作实现代码
2010/06/22 Javascript
js中arguments,caller,callee,apply的用法小结
2014/01/28 Javascript
jQuery实现的五子棋游戏实例
2015/06/13 Javascript
js实现简单的联动菜单效果
2015/08/19 Javascript
纯js实现手风琴效果
2020/04/17 Javascript
瀑布流的实现方式(原生js+jquery+css3)
2020/06/28 Javascript
Angularjs 设置全局变量的方法总结
2016/10/20 Javascript
bootstrap下拉分页样式 带跳转页码
2018/12/29 Javascript
[02:03]DOTA2亚洲邀请赛 HGT战队出场宣传片
2015/02/07 DOTA
[01:06:25]Secret vs Liquid 2018国际邀请赛淘汰赛BO3 第一场 8.25
2018/08/29 DOTA
Python操作列表的常用方法分享
2014/02/13 Python
全面解读Python Web开发框架Django
2014/06/30 Python
Python常用模块sys,os,time,random功能与用法实例分析
2020/01/07 Python
python通过opencv实现图片裁剪原理解析
2020/01/19 Python
Python使用type动态创建类操作示例
2020/02/29 Python
python实现将列表中各个值快速赋值给多个变量
2020/04/02 Python
python 实现任务管理清单案例
2020/04/25 Python
Python request使用方法及问题总结
2020/04/26 Python
HTML5 与 XHTML2
2008/10/17 HTML / CSS
移动端Html5页面生成图片解决方案
2018/08/07 HTML / CSS
税务专业毕业生自荐信
2013/11/10 职场文书
商务主管岗位职责
2013/12/08 职场文书
信息专业毕业生五年职业规划参考
2014/02/06 职场文书
自主招生教师推荐信
2014/05/10 职场文书
医生个人年度总结
2015/02/28 职场文书
2015年度保密工作总结
2015/04/24 职场文书
学者《孟子》名人名言
2019/08/09 职场文书