Reputation: 2009
I've created a class like the following:
class Simon:
name = 'Simon'
@classmethod
def says(cls, sentence):
return '%s says: %s' % (cls.name, sentence)
If I want Simon say sit down, I can do this:
>>> Simon.says('sit down')
'Simon says: sit down'
To substitute Simon with another name, say, Eva, I can subclass it like this:
class Eva(Simon):
name = 'Eva'
And the result:
>>> Eva.says('stand up')
'Eva says: stand up'
Now I want to change says to said by creating a decorator called to_past_tense
:
class Eva(Simon):
name = 'Eva'
def to_past_tense(self, func):
def wrapper(*arg, **kw):
present_tense = func(*arg, **kw)
past_tense = present_tense.replace('says', 'said')
return past_tense
return wrapper
@classmethod
def says(cls, *arg, **kw):
return cls.to_past_tense(cls, Simon.says)(*arg, **kw)
If I do this:
>>> Eva.says('stand up')
what I'm expecting is this:
'Eva said: stand up'
but in fact I got this
'Simon said: stand up'
How can I override the value?
And, please, help me improve the title if it isn't precise and clear, thank you!
Upvotes: 0
Views: 2420
Reputation: 1123400
You are using Simon.says
, retrieving a bound class.
If you wanted to get the overridden class method but have it bind to the current class, use a super()
proxy object:
@classmethod
def says(cls, *arg, **kw):
return cls.to_past_tense(cls, super().says)(*arg, **kw)
The super()
object will search the MRO of the class, find the says
method on Simon
, then bind it to the cls
object for you, so the cls.name
value is still looked up from Eva
:
>>> class Simon:
... name = 'Simon'
... @classmethod
... def says(cls, sentence):
... return '%s says: %s' % (cls.name, sentence)
...
>>> class Eva(Simon):
... name = 'Eva'
... def to_past_tense(self, func):
... def wrapper(*arg, **kw):
... present_tense = func(*arg, **kw)
... past_tense = present_tense.replace('says', 'said')
... return past_tense
... return wrapper
... @classmethod
... def says(cls, *arg, **kw):
... return cls.to_past_tense(cls, super().says)(*arg, **kw)
...
>>> Eva.says('Hello')
'Eva said: Hello'
Upvotes: 2
Reputation: 599788
I'm not entirely sure what you are trying to achieve here, but I suppose you need to pass cls.says
to the method:
return cls.to_past_tense(cls, cls.says)(*arg, **kw)
Upvotes: 0