I would like to customize the my inherited methods are called.
Here's an example code:
class First(object):
def get(self):
print('getting from first')
def set(self):
print('setting to first')
class Second(object):
def get(self):
print('getting from second')
def set(self):
print('setting to second')
class Third(First, Second):
def get(self):
super(Third, self).get()
def set(self):
super(Third, self).set()
Now the behavior i would like to have is such that:
third = Third()
third.get() # -> should print 'getting from first'
third.set() # -> should print 'setting to second'
Right now the mro shows:
Third.__mro__ -> (__main__.Third, __main__.First, __main__.Second, object)
We can see that methods inside main.First always get called first. While what i want is that main.Second gets called first during execution of set() method.
And here's my attempt to solve this, trying to modify the MRO of Third class:
The idea is to swap the two positions of the two classes and see if it can work.
First, a swap()
helper function.
def swap(index1, index2, mro_tuple):
l = list(mro_tuple)
temp = l[index1]
l[index1] = l[index2]
l[index2] = temp
return tuple(l)
Then during implemenation of set()
method, i attempt to modify the mro of the underlying class.
class Third(First, Second):
def get(self):
super(Third, self).get()
def set(self):
self.__class__.__mro__ = swap(1, 2, self.__class__.__mro__) # swap here..
super(Third, self).set() # then call method**
In [43]: third = Third()
In [44]: third.get()
getting from first
In [45]: third.set()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-53-c82ac1a0d5bc> in <module>
----> 1 third.set()
<ipython-input-50-00c9baff0d57> in set(self)
4
5 def set(self):
----> 6 self.__class__.__mro__ = swap(1, 2, self.__class__.__mro__) # swap here..
7 super(Third, self).set() # then call method
8
AttributeError: readonly attribute
It shows that the __mro__
attribute cannot be reset.
Is there anyway to implement this behavior, in a convenient way ?
Your best bet is probably to have Third
explicitly use the Second
implementation:
class Third(First, Second):
set = Second.set
although the fact that you're asking this at all is a warning sign that you may have picked a bad class hierarchy.