Reputation: 860
I'd like to modify a class method to do some things in addition to the original method call. I have a toy example posted below.
Example:
class str2(str):
def __init__(self, val):
self.val = val
def upper(self):
print('conveting to upper')
return self.upper()
x = str2('a')
print(x.upper())
This does what I should have expected and gives a maximum recursion depth error. Is it possible to modify the upper
method so that it prints some text before calling the actual str.upper
method, while ideally keeping the name the same?
I've been wondering if this is the situation to use a decorator, but I am not familiar enough with them to have a clear idea on how to do this.
Upvotes: 0
Views: 101
Reputation: 3974
As @Schalton stated, there is a way to do it without having to inherit from str by using decorators. Consider this snippet:
def add_text(func):
def wrapper(*args, **kwargs):
print('converting to upper')
return func(*args)
return wrapper
class str2:
def __init__(self, val):
self.val = val
@add_text
def upper(self):
return self.val.upper()
instance = str2('a')
print(instance.upper())
The great advantage of this is that the wrapper is reusable, e.g. if you have another class that you want to modify with the exact same behavior, you can just add the @decorator and don't have to redo all the work. Also, removing the additional functionality gets also easier.
Upvotes: 0
Reputation: 22294
In the method str2.upper
you are calling str2.upper
which in turn calls str2.upper
which... You see where this is going.
What you probably intended to so was to call str.upper
from str2.upper
. This is done by using super
. Calling super()
returns an object which delegates method calls to the parent classes.
class str2(str):
def upper(self):
print('converting to upper')
return super().upper()
Upvotes: 1
Reputation: 71570
The solution would be:
class str2(str):
def __init__(self, val):
self.val = val
def upper(self):
print('conveting to upper')
return str.upper(self.val)
x = str2('a')
print(x.upper())
in upper
function you just print it then go to same function again and again
this makes it that it will keep printing
it raises an error at the end because python basically has enough of this
use the method-descriptor (<method 'upper' of 'str' objects>
) to use it so it doesn't confuse it with self
use that because it will still be calling the real str
class (not the metaclass)
I am also blaming myself that why i didn't think of:
class str2(str):
def __init__(self, val):
self.val = val
def upper(self):
print('conveting to upper')
return self.val.upper()
x = str2('a')
print(x.upper())
Upvotes: 1
Reputation: 3104
Research "Mapping" and "decorators" - I think there's an easier/more pythonic way to do what you're trying to do.
Upvotes: 0