If each class's __init__ is used to set default values, it requires that one use super() or explicit parentclass.__init__() calls . Such ugly boilerplate can be avoided with this recipe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | class Base(object):
def __init__(self, *args, **kwds):
self.autosetup(self.__class__, [], **kwds)
def setup(self, **kwds):
pass
def autosetup(self, cls, called, **kwds):
for base in cls.__bases__:
try:
b = base.setup
except AttributeError:
pass
else:
if b not in called:
called = self.autosetup(base, called, **kwds)
cls.setup(self, **kwds)
called.append(cls.setup)
return called
# Sample Usage
class A(Base):
def setup(self, foo, **kwds):
print "A",foo
class B(Base):
def setup(self, blah, **kwds):
print "B", blah
class C(B):
def setup(self, blech, **kwds):
print "C", blech
class D(A, C):
def setup(self, frog, **kwds):
print "D", frog
class E(C):
pass
class F(D, E):
def setup(self, toad, foo, frog, **kwds):
print "F", foo, frog, toad
x = F(foo=1, blah=2, blech=3, frog=4, toad=5)
|
Using super() is ugly and painful, and for one of the most common cases - allowing classes to set default values - unnecessary.
It was originally created for game objects where a user class can inherit from a large number of mixins, eg: "Cake(Base, CanWriteOn, CanBurn, CanTake, CanEat)...", but should be of general use. The same technique could be used to do an autoverify() after the autosetup(), to check values set by the user that aren't otherwise checked.
There's some discussion on using super() at http://mail.python.org/pipermail/python-dev/2005-January/050656.html
Tim Delaney has an autosuper recipe at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/286195