I need to find an elegant way to do 2 kinds of MixIns.
First:
class A(object):
def method1(self):
do_something()
Now, a MixInClass
should make method1
do this: do_other()
-> A.method1()
-> do_smth_else()
- i.e. basically "wrap" the older function. I'm pretty sure there must exist a good solution to this.
Second:
class B(object):
def method1(self):
do_something()
do_more()
In this case, I want MixInClass2
to be able to inject itself between do_something()
and do_more()
, i.e.: do_something()
-> MixIn.method1
-> do_more()
. I understand that probably this would require modifying class B
- that's ok, just looking for simplest ways to achieve this.
These are pretty trivial problems and I actually solved them, but my solution is tainted.
Fisrt one by using self._old_method1 = self.method1(); self.method1() = self._new_method1();
and writing _new_method1()
that calls to _old_method1()
.
Problem: multiple MixIns will all rename to _old_method1 and it is inelegant.
Second MixIn one was solved by creating a dummy method call_mixin(self): pass
and injecting it between calls and defining self.call_mixin()
. Again inelegant and will break on multiple MixIns..
Any ideas?
Thanks to Boldewyn, I've found elegant solution to first one (I've forgot you can create decorators on-the-fly, without modifying original code):
class MixIn_for_1(object):
def __init__(self):
self.method1 = self.wrap1(self.method1)
super(MixIn_for_1, self).__init__()
def wrap1(self, old):
def method1():
print "do_other()"
old()
print "do_smth_else()"
return method1
Still searching for ideas for second one (this idea won't fit, since I need to inject inside of old method, not outside, like in this case).
Solution for second is below, replacing "pass_func" with lambda:0
.
I think, that can be handled in quite a Pythonic way using decorators. (PEP 318, too)
Here is another way to implement MixInClass1, MixinClass2:
Decorators are useful when you need to wrap many functions. Since MixinClass1
needs to wrap only one function, I think it is clearer to monkey-patch:
Using double underscores for __old_method1
and __method1
plays a useful role in MixInClass1
. Because of Python's name-mangling convention, using the double underscores localizes these attributes to MixinClass1
and allows you to use the very same attribute names for other mix-in classes without causing unwanted name-collisions.
class MixInClass1(object):
def __init__(self):
self.__old_method1,self.method1=self.method1,self.__method1
super(MixInClass1, self).__init__()
def __method1(self):
print "pre1()"
self.__old_method1()
print "post1()"
class MixInClass2(object):
def __init__(self):
super(MixInClass2, self).__init__()
def method1_hook(self):
print('MixIn method1')
class Foo(MixInClass2,MixInClass1):
def method1(self):
print "do_something()"
getattr(self,'method1_hook',lambda *args,**kw: None)()
print "do_more()"
foo=Foo()
foo.method1()
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