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 面向对象基础(类、实例、方法、属性封装)
python是面向对象语言,一切皆对象. 面向过程: 变量和函数. “散落” 在文件的各个位置,甚至是不同文件中.看不出变量与函数的相关性,非常不利于维护,设计模式不清晰. 经常导致程序员,忘记某个变 ...
- Python学习:类和实例
Python学习:类和实例 本文作者: 玄魂工作室--热热的蚂蚁 类,在学习面向对象我们可以把类当成一种规范,这个思想就我个人的体会,感觉很重要,除了封装的功能外,类作为一种规范,我们自己可以定制的规 ...
- 动态布局--动态修改RelativeLayout宽高的方法
本文实例讲述了Android编程动态修改RelativeLayout宽高的方法.分享给大家供大家参考,具体如下: 我们经常会动态修改RelativeLayout的宽高,这样的代码,比较简单,就是修改R ...
- python中的类和实例
今天花了两个多小时后搜索相关博客看了看python中有关类和实例的介绍,差不多大概明白了. python中的类和c++中的类是一样的,不同之处就是c++的类,如果含有成员变量,并且成员变量发生变化后, ...
- 动态修改Python类和实例的方法(转)
相信很多朋友在编程的时候都会想修改一下已经写好的程序行为代码,而最常见的方式就是通过子类来重写父类的一些不满足需求的方法.比如说下面这个例子. class Dog: def bark(self): p ...
- python动态获取对象的属性和方法 (转载)
首先通过一个例子来看一下本文中可能用到的对象和相关概念. #coding:utf-8 import sys def foo():pass class Cat(object): def __init__ ...
- Python学习_11_类和实例
类和实例 类是对象创建实例的模板,而实例则是对象的实体.类使用class关键字定义: class MyClass: pass python中创建实例直接使用工厂函数(类名加上一对括号),和其他的 ...
- Python面试题之Python中的类和实例
0x00 前言 类,在学习面向对象我们可以把类当成一种规范,这个思想就我个人的体会,感觉很重要,除了封装的功能外,类作为一种规范,我们自己可以定制的规范,从这个角度来看,在以后我们学习设计模式的时候, ...
- python动态获取对象的属性和方法 (转)
转自未知,纯个人笔记使用 首先通过一个例子来看一下本文中可能用到的对象和相关概念. #coding:utf-8 import sys def foo():pass class Cat(object): ...
随机推荐
- [学习笔记—Objective-C]《Objective-C-基础教程 第2版》第二章~第七章
在看完<Objective-C 程序设计 第6版>之后,看了一些关于iOS开发职位的面试题,发现自身基础非常是不牢,于是打算以查缺补漏的方式阅读还有一本关于Objective-C的基础书籍 ...
- 使用golang来设计我们的Ubuntu Scope
我们知道golang越来越被非常多的开发人员来开发应用.go语言也能够用于开发Ubuntu Scope. 在今天的教程中.我们将具体介绍怎样使用go语言来开发我们的Scope.这对于非常多的不太熟悉C ...
- 自定cell(XIB)团购思路
自定cell(XIB)团购思路 步骤一.先解析plist文件,创建model层数据. - (instancetype)initWithDict:(NSDictionary *)dict { s ...
- javase - 点餐系统
public class OrderMsg { public static void main(String[] args) throws Exception { /** * 订餐人姓名.选择菜品.送 ...
- jQuery - 选中复选框则弹出提示框
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- App/Activity/Screen Orientation
测试android屏幕方向的小Demo 1.首先我们在values下面新建文件arrays.xml(用来在下拉列表中显示) <?xml version="1.0" encod ...
- Android Calendar的运用
import java.text.DateFormat; import java.text.ParsePosition; import java.text.SimpleDateFormat; impo ...
- 动态规划---区间dp
今天写内网题,连着写了两道区间dp,这里就总结一下. 区间dp思想主要是先枚举f[i][j]中的i,再枚举j,再枚举一个1~j之间的变量k,一般是f[i][j] = max(f[i][j],f[i][ ...
- c++之——————各种变量
对我们程序员来讲,“变量”和“对象”是可以相互互换使用的.-------------开篇之词. 变量:提供一个具有名字的可供程序操作的存储空间.由类型说明符和其后紧跟的数个列表组成,其中变量名之间使用 ...
- [Spring] Spring Boot 生态