Python类的动态修改的实例方法
作者:平和的心 发布时间:2021-07-03 12:16:15
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)
现在我们的方法已经和实例绑定了,大功告成!
总结
运行中替换或者添加方法是非常有用的,比如说在单元测试中,有些负责和外界服务通信的函数就需要替换掉,方便测试。这个技巧不仅很常用,而且在你最终决定要修改代码之前还可以保持代码的可维护性,是一个非常重要的技巧。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
来源:http://www.cnblogs.com/ajianbeyourself/p/4916254.html
猜你喜欢
- golang的defer优雅又简洁, 是golang的亮点之一。defer在声明时不会立即执行,而是在函数return后,再按照先进后出的原
- 本文实例为大家分享了Go实现文件上传和下载的具体代码,供大家参考,具体内容如下一.文件上传文件上传:客户端把上传文件转换为二进制流后发送给服
- 前言用Python如何写一个接口呢,首先得要有数据,可以用我们在网站上爬的数据,在上一篇文章中写了如何用Python爬虫,有兴趣的可以看看:
- 一、创建一个项目如果这是你第一次使用Django,那么你必须进行一些初始设置。也就是通过自动生成代码来建立一个Django项目--一个Dja
- 在使用flask部署Keras,tensorflow等框架时候,经常出现FailedPreconditionError: Attemptin
- 前言我们把可能发生错误的语句放在try模块里,用except来处理异常。except可以处理一个专门的异常,也可以处理一组圆括号中的异常,如
- 怎样判断一个JavaScript变量是array还是obiect? 答案: 1、如果你只是用typeof来检查该变量,不论是array还是o
- 最近在写博客,刚好写到用户注册注销模块,觉得这一方面还是挺有趣的。当尝试掀开 Django 的源代码时一切 API 就不会变得那么摸不着。顺
- 引言Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型结构体是由一系列具有相同类型或不同类型的数据构成的
- 于是写测试程序。。。不行 下载最新的ODBC。。。还是不行 通过sql plus查询。。。咦?竟然也查不到。。。 于是,折腾。。。折腾。。。
- 编程语言中反射的概念在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(s
- 这篇文章主要介绍了js简单的分页器插件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参
- 笔者在网上找了很多关于VSCODE配置Go语言的教程,但是由于版本等种种问题,最终都已失败告终。无奈只能在官方文档上寻求帮助,现在终于可以了
- 一、调用百度接口进行人脸属性识别安装好baidu-aip模块,获取了百度AI接口密钥后,即可调用百度接口进行人脸属性识别了。首先以杨紫的图片
- Python lxml安装失败针对windows系统LXML安装失败而且pip升级也失败解决方案原因可能是pip没有安装到python我们需
- Angular中根据适用场景定义了很多生命周期函数,其本质上是事件的响应函数,其中最常用的就是ngOnInit。但在TypeScript或E
- documentFragment 是一個無父對象的document對象.他支持以下DOM2方法:appendChild, cloneNode
- 思路:队列使用说明:multiprocessing.Queue()#用于进程间通信,单主进程与子进程无法通信(使用进程池时尽量不要使用这个)
- $str = '中华人民共和国123456789abcdefg'; echo preg_match("/^[\u4
- 1、Python函数函数是Python为了代码最大程度的重用和最小化代码冗余而提供的基本程序结构,用于将相关功能打包并参数化Python中可