如何增强Python对象的方法?
我有一个包含 Spam 对象的列表:
class Spam:
def update(self):
print('updating spam!')
其中有些可能是 SpamLite 对象:
class SpamLite(Spam):
def update(self):
print('this spam is lite!')
Spam.update(self)
我想从这个列表中随便拿一个对象,然后在它的更新方法中加点东西,类似于:
def poison(spam):
tmp = spam.update
def newUpdate(self):
print 'this spam has been poisoned!'
tmp(self)
spam.update = newUpdate
我希望 spam.update() 现在可以打印:
this spam has been poisoned!
updating spam!
或者
this spam has been poisoned!
this spam is lite!
updating spam!
这取决于它是 SpamLite 还是普通的 Spam。
但是这样做不行,因为 spam.update() 不会自动传入 self 参数,而且如果 tmp 超出作用域或者发生变化,就不会调用旧的更新方法。有没有办法可以做到这一点呢?
4 个回答
0
在Python的世界里,猴子补丁(Monkey Patching)是不太受欢迎的做法。
你其实应该使用混入(Mixin)的方法,并且利用多重继承。
这样你就可以动态地替换(更新)父类,以达到你想要的效果。
3
另一种方法是使用 MethodType:
class Spam:
def update(self):
print('updating spam!')
class SpamLite(Spam):
def update(self):
print('this spam is lite!')
Spam.update(self)
def poison(spam):
import types
tmp = spam.update
def newUpdate(self):
print 'this spam has been poisoned!'
tmp()
newUpdate = types.MethodType(newUpdate, spam, Spam)
spam.update = newUpdate
spam = Spam()
spam_lite = SpamLite()
poison(spam)
poison(spam_lite)
spam.update()
print
spam_lite.update()
4
def poison(spam):
tmp = spam.update
def newUpdate():
print 'this spam has been poisoned!'
tmp()
spam.update = newUpdate
完整的脚本:
class Spam:
def update(self):
print('updating spam!')
class SpamLite(Spam):
def update(self):
print('this spam is lite!')
Spam.update(self)
def poison(spam):
tmp = spam.update # it is a bound method that doesn't take any arguments
def newUpdate():
print 'this spam has been poisoned!'
tmp()
spam.update = newUpdate
from operator import methodcaller
L = [Spam(), SpamLite()]
map(methodcaller('update'), L)
map(poison, L)
print "*"*79
map(methodcaller('update'), L)
输出:
updating spam! this spam is lite! updating spam! ******************************************************************************* this spam has been poisoned! updating spam! this spam has been poisoned! this spam is lite! updating spam!