I have a class in the main project I don't want to change.
class A():
def __init__(self, firstname, lastname):
self.firstname = firstname
self.lastname = lastname
def name(self):
# this method could be much more complex
return self.lastname.upper()
I'm trying to build a plugin mechansim. So far so good, I have an extension point like this:
if __name__ == '__main__':
''' The main project has an extension point that allows me to do'''
# for each class extension such as AExtended:
A.name = AExtended.name
''' After the extensions are loaded, some behaviours may be changed'''
a = A("John", "Doe")
print(a.name())
A plugin can be written like this:
class AExtended(A):
''' This is an extension I provide through a plugin mechanism
'''
def name(self):
return self.firstname + ' ' + self.lastname.upper()
This all works very well. I now get "John DOE".
My problem is that the original name()
method can be quite complex. In other words, I can't afford to call self.lastname.upper()
in the AExtended
. I'd like to call the "super" method, which does not exist any more, because it has been overwritten.
How can I change my code, in order to achieve something like this:
class AExtended(A):
def name(self):
# I'm looking for a way to call the base implementation that was in A.name()
return self.firstname + ' ' + parent.name()
Thanks for your help!
Edit: Some explanations of what I try to do.
A
. I can't afford to change existing consumers of AA
that could be changed, I'd like plugins to have full control and responsibilityAExtended
does not have to inherit from A
, but it was an easy way to access self.firstname
. I have no problem following a different design pattern if it can help.I have a workaround, but it's not very elegant and hard to generalize
class AExtended(A):
def name(self):
# I'm looking for a way to call the base implementation that was in A.name()
return self.firstname + ' ' + self.parentname()
#in main
A.parentname = A.name
A.name = AExtended.name
This is what we call a 'decorator' pattern. Replace the original reassignment of name to have it call a function instead, which takes the original. It then returns a new function.
def name_decorator(method):
def decorate_name(self=None):
return stuff + method(self)
return decorate_name
A.name = name_decorator(A.name)
Later, calling A.name
will call decorate_name
with self
as the current instance and method
will be available to it which points to the function at the time of the reassignment.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With