问题
MyClass
is defined in module.py
. There is no way we can modify it. But we do know the Class definition looks like this:
class MyClass:
def method(self, msg):
print 'from method:', msg
I start my script with importing the module and then declaring an object's instance:
import module
foo = module.MyClass()
Then I write my own function:
def function(msg):
print 'from function:', msg
Now, every time foo.method('')
is used I want to call function()
so it prints the same message too.
Would this situation be referred as the monkey patching
? How to achieve what is needed?
回答1:
Yes, it's called monkey-patching.
This is basically decoration, but done manually after the class is already defined.
from functools import wraps
def wrapper(f):
@wraps(f)
def wrapped(*args, **kwargs):
myFunction()
return f(*args, **kwargs)
return wrapped
MyClass.printThis = wrapper(MyClass.printThis)
It will affect all instances of MyClass
, even those that were created before the patch was applied.
If you don't need to dynamically modify runtime behaviour, avoid monkey-patching and prefer to use inheritance to customise behaviour, as suggested in the comments. It's less hacky.
回答2:
This is an alternative to wim's answer that also involves monkey-patching. However, it does it through functionality provided by unittest.mock
. The advantage of this approach is that a context manager is used to automatically apply and remove the patch within a limited scope:
from unittest import mock
# This class would be defined in some third-party library
class MyClass:
def method(self, msg):
print('from method:', msg)
def function(msg):
print('from function:', msg)
old_method = MyClass.method
def new_method(self, msg):
old_method(self, msg)
function(msg)
# The patch is only applied within this scope
with mock.patch.object(MyClass, 'method', new_method):
foo = MyClass()
foo.method('message with patched')
# By this point MyClass is "back to normal"
print('---')
foo.method('message with original')
Output
from method: message with patched
from function: message with patched
---
from method: message with original
回答3:
You could subclass it as well:
class MyClass:
def method(self, msg):
print 'from method:', msg
def function(msg):
print 'from function:', msg
class MyNewClass(MyClass):
def method(self, msg):
function(msg)
MyClass.method(self, msg)
And use it like:
>>> a = MyNewClass()
>>> a.method("test")
from function: test
from method: test
Or, if you want to make your class a "new-style" class (for Python 2 - judging by your print statements) - just have MyClass
inherit from object
and then you can user super
:
class MyClass(object): # object added here
def method(self, msg):
print 'from method:', msg
def function(msg):
print 'from function:', msg
class MyNewClass(MyClass):
def method(self, msg):
function(msg)
super(self.__class__, self).method(msg) # super added here
回答4:
Ended up with this solution till there is better one posted...
class MyClass:
def method(self, msg):
print 'from method:', msg
def function(msg, callback):
print 'from function:', msg
callback(msg)
foo = MyClass()
foo.function = function
foo.function(msg='message', callback=foo.method)
来源:https://stackoverflow.com/questions/41904124/how-to-extend-class-instance