Calling __init__ with multiple inheritance
Michael Spencer
mahs at telcopartners.com
Mon Mar 28 12:55:47 EST 2005
phil_nospam_schmidt at yahoo.com wrote:
> 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
>
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:
"""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
More information about the Python-list
mailing list