Reputation: 44776
In Python, I am using a framework that lets me hook into a lifecycle like so:
class MyView(BaseView):
def pre_save(self):
print "view presave"
I want to write a mixin to do something in pre_save
, but I already have lots of code in lots of classes using pre_save
as above, without calling super()
. If I add in my mixin like so:
class MyMixin(object):
def pre_save(self):
print "mixin presave"
class MyView(MyMixin, BaseView):
def pre_save(self):
print "view presave"
It naturally overwrites the mixin, and prints "view presave" only. Is there another, sneakier way I can write MyMixin
to not force all client views to remember to call super()
?
Upvotes: 0
Views: 1019
Reputation: 170
This answer is a proof of concept, not a recommendation. DO NOT DO THIS IN PRODUCTION CODE. You will create maintenance nightmare. I agree with those commenting on your question that the only safe approach is editing the derived classes.
That said, it is technically possible using a metaclass.
def do_evil(self, method):
print "doing evil"
MyMixin.pre_save(self)
method(self)
class ConcentratedEvil(type):
tainted_classes = ['MyView'] # Add others as needed
def __new__(mcs, name, bases, dict):
if name in mcs.tainted_classes:
print "tainting {0} with the power of evil".format(name)
old_method = dict['pre_save']
dict['pre_save'] = lambda x: do_evil(x, old_method)
print dict.keys()
return type.__new__(mcs, name, bases, dict)
class BaseView(object):
pass
class MyMixin(object):
__metaclass__ = ConcentratedEvil
def pre_save(self):
print "mixin presave"
class MyView(MyMixin, BaseView):
def pre_save(self):
print "view presave"
At which point you can do:
>>> view = MyView()
>>> view.pre_save()
doing evil
mixin presave
view presave
>>>
I think this only works if MyMixin is at the front of the base class list.
Upvotes: 1