Last active
February 4, 2020 03:43
-
-
Save nmfzone/9345fe26bb43db65bd5c2d966c1c86d2 to your computer and use it in GitHub Desktop.
Monkey Patch: Override method without extending class in Python (e.g. Patch method, Override core method)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def override_method(cls, after=True): | |
def decorator(func): | |
new_parent_method_name = '_' + func.__name__ + '_parent' | |
setattr(cls, new_parent_method_name, getattr(cls, func.__name__)) | |
@wraps(func) | |
def wrapper(self, *args, **kwargs): | |
if after: | |
parent_result = getattr(self, new_parent_method_name)(*args, **kwargs) | |
return func(self, parent_result, *args, **kwargs) | |
elif after == False: | |
func(self, *args, **kwargs) | |
return getattr(self, new_parent_method_name)(*args, **kwargs) | |
return func(self, *args, **kwargs) | |
setattr(cls, func.__name__, wrapper) | |
return func | |
return decorator |
It's fine (actually the correct way) when you only need to override method in that class.
But, what about when the BaseClass
is a core class? Then it's gets used everywhere, and has other core class that override it?
This is useful when you only want to modify / override the method in the root class.
@override_method(BaseClass) # just like ClassOne does
def foo(self, parent_result, x, y): # you had to define `parent_result` argument, it's the parent result return value.
return parent_result * 2
@override_method(BaseClass, False) # just like ClassTwo does
def foo(self, x, y): # you should not define `parent_result` argument, it's just used when `after=True`
x = x - 2 # this is just for example. It will not working as expected, since it's local variable.
@override_method(BaseClass, None) # just like ClassThree does
def foo(self, x, y): # you should not define `parent_result` argument, it's just used when `after=True`
return ((x - 2) + y) * 2
You just need to place that code somewhere, the place that your app always access it no matter what, for example in __init__.py
file.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When you override method in a class, you may write something like these: