I\'ve found myself in an unusual situation where I need to change the MRO of a class at runtime.
The code:
class A(object):
def __init__(self):
I don't know if it's relevant to the specific problem, but it seems to me that changing the MRO on the fly like that could be risky in a concurrent program, and could definitely have issues if any of these objects turn out to be created recursively.
A non-MRO-based solution occurs to me, depending on the nature of the errors this code would have encountered. (Keeping in mind that this is belated. Perhaps somebody else will want a different answer.)
Basically, each hello() method on B would be wrapped in a decorator. Something along the lines of
class deferring(object):
def __init__(self, function):
self.function = function
def __get__(self, instance, owner):
# Return an unbound method, or whatever, when called from B.
if instance is None:
return self.function.__get__(None, owner)
else:
# Indicate that an instance is ready via a flag.
# May need to tweak this based on the exact problem.
if hasattr(instance, '_set_up'):
return self.function.__get__(instance, owner)
else:
# Walk the mro manually.
for cls in owner.__mro__:
# Crazy inefficient. Possible to mitigate, but risky.
for name, attr in vars(cls).items():
if attr is self:
break
else:
continue
return getattr(super(cls, instance), name)
else:
raise TypeError
If you don't want to go the descriptor route, it's also possible to do something like
def deferring(function):
def wrapped(self, *args, **kwargs):
if hasattr(self, '_set_up'):
return function(self, *args, **kwargs)
else:
for cls in type(self).__mro__:
for name, attr in vars(cls).items():
if attr is function:
break
else:
continue
return getattr(super(cls, self), name)(*args, **kwargs)
else:
raise TypeError
return wrapped