How can I extend the method of a Python object?

I have a list of Spam objects:

class Spam: def update(self): print('updating spam!') 

some of them may be SpamLite objects:

 class SpamLite(Spam): def update(self): print('this spam is lite!') Spam.update(self) 

I would like to be able to take an arbitrary object from the list and add something to it update method, for example:

 def poison(spam): tmp = spam.update def newUpdate(self): print 'this spam has been poisoned!' tmp(self) spam.update = newUpdate 

I want spam.update () to now either print:

 this spam has been poisoned! updating spam! 

or

 this spam has been poisoned! this spam is lite! updating spam! 

depending on whether it was SpamLite or just spam.

But this does not work, because spam.update () will not be automatically passed in the self argument, but because if tmp leaves visibility or changes, then it is not called by the old update. Is there a way I can do this?

+4
source share
4 answers
 def poison(spam): tmp = spam.update def newUpdate(): print 'this spam has been poisoned!' tmp() spam.update = newUpdate 

Full Script:

 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) 

Output:

  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!
+4
source

Another approach: 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() 
+3
source

MonkeyPatching frowned in the python world.

You really should use the Mixin approach and use multiple inheritance.

Then you can dynamically replace (update) the parents to achieve the desired effect.

0
source

Use decorators like this:

 def method_decorator(f): def wrapper(self, *args, **kwargs): print('this spam has been poisoned!') return f(self) return wrapper class Spam: def update(self): print('updating spam!') @method_decorator def update2(self): print('updating spam!') Spam().update() Spam().update2() 

Fingerprints:

 updating spam! this spam has been poisoned! updating spam! 

If you want to know more about decorators, read the following: http://www.drdobbs.com/web-development/184406073

The above is not a "good citizen" decorator, read the article to know how to write it. Be sure to also check out the decorator library: http://pypi.python.org/pypi/decorator

NTN

0
source

All Articles