if you're going to be doing a bunch of these, you could define your own variant of the super type that calls all the methods in the mro with the given name. Below is a minor modification to the pure-python version of built-in super that illustrates this. There is no error-checking (e.g., if an attribute is callable in one class, and not callable in another you will hit problems) and it's not tested beyond what you see:What if I want to call other methods as well? Modifying your example a bit, I'd like the reset() method call of Child to invoke both the Mother and Father reset() methods, without referencing them by name, i.e., Mother.reset(self).
------------------- class Mother(object): def __init__(self, p_mother, **more): print "Mother", p_mother, more super(Mother, self).__init__(p_mother=p_mother, **more) def reset(self): print 'resetting Mother'
class Father(object): def __init__(self, p_father, **more): print "Father", p_father, more super(Father, self).__init__(p_father=p_father, **more) def reset(self): print 'resetting Father'
class Child(Mother, Father): def __init__(self, p_mother, p_father, **more): print "Child", p_mother, p_father, more super(Child, self).__init__(p_mother=p_mother, p_father=p_father, **more) def reset(self): print 'resetting Child'
# I would like to invoke both Mother.reset() # and Father.reset() here, but it doesn't work. print 'trying "super"' super(Child, self).reset()
# These next two do work, but require referencing # Mother and Father directly. print "calling directly" Mother.reset(self) Father.reset(self)
a = Child(1, 2) a.reset() -------------------
Thanks, Phil
"""Hack on Super defined in http://python.org/2.2/descrintro.html to call all super-class methods"""
class PolySuper(object): def __init__(self, type, obj=None): self.__type__ = type self.__obj__ = obj def __get__(self, obj, type=None): if self.__obj__ is None and obj is not None: return Super(self.__type__, obj) else: return self def __getattr__(self, attr): if isinstance(self.__obj__, self.__type__): starttype = self.__obj__.__class__ else: starttype = self.__obj__ mro = iter(starttype.__mro__) for cls in mro: if cls is self.__type__: break # Note: mro is an iterator, so the second loop # picks up where the first one left off! for cls in mro: if attr in cls.__dict__: x = cls.__dict__[attr] if hasattr(x, "__get__"): x = x.__get__(self.__obj__)
# return x # We want all the resolved methods, in order yield x #raise AttributeError, attr
# Add this crude callable interface def __call__(self, attr, *args, **kw): methods = list(self.__getattr__(attr)) return [method(*args, **kw) for method in methods]
Then, your classes get defined like so:
class Mother(object): def __init__(self, p_mother, **more): print "Mother", p_mother, more def reset(self): print 'resetting Mother'
class Father(object): def __init__(self, p_father, **more): print "Father", p_father, more def reset(self): print 'resetting Father'
class Child(Mother, Father):
def __init__(self, p_mother, p_father, **more):
print "Child", p_mother, p_father, more
PolySuper(Child, self)("__init__", p_mother = p_mother, p_father = p_father)
def reset(self):
print 'resetting Child'
PolySuper(Child, self)("reset")
>>> c = Child("M1","F1") Child M1 F1 {} Mother M1 {'p_father': 'F1'} Father F1 {'p_mother': 'M1'} >>> c.reset() resetting Child resetting Mother resetting Father >>>
HTH Michael
-- http://mail.python.org/mailman/listinfo/python-list