When the Sub class' initialize method is executed it squashes the Base class'. What we want is for both to be called:
class Base(object): def __init__(self): print "foo" class Sub(Base): def __init__(self): print "bar"
class Sub(Base): def __init__(self): Base.__init__(self) print "bar"
Unfortunately, we can't make the person extending our class call the super class. A poor man's factory pattern alleviates the possibility of subtype implementers forgetting initialization. Consider:
class AbstractClass(object): '''Abstract base class template, implementing factory pattern through use of the __new__() initializer. Factory method supports trivial, argumented, & keyword argument constructors of arbitrary length.''' __slots__ = ["baseProperty"] '''Slots define [template] abstract class attributes. No instance __dict__ will be present unless subclasses create it through implicit attribute definition in __init__() ''' def __new__(cls, *args, **kwargs): '''Factory method for base/subtype creation. Simply creates an (new-style class) object instance and sets a base property. ''' instance = object.__new__(cls) instance.baseProperty = "Thingee" return instance
This base class can be extended trivially, using only three (3) lines of code san-commment, as follows:
class Sub(AbstractClass): '''Subtype template implements AbstractClass base type and adds its own 'foo' attribute. Note (though poor style, that __slots__ and __dict__ style attributes may be mixed.''' def __init__(self): '''Subtype initializer. Sets 'foo' attribute. ''' self.foo = "bar"
Note that though we didn't call the super-class' constructor, the baseProperty will be initialized:
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) [GCC 4.2.1 (Apple Inc. build 5646)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> from TestFactory import * >>> s = Sub() >>> s.foo 'bar' >>> s.baseProperty 'Thingee' >>>
As its comment indicates, the base class AbstractClass need not use slots, it could just as easily 'implicitly' define attributes by setting them in its new() initializer. For instance:
instance.otherBaseProperty = "Thingee2"
would work fine. Also note that the base class' initializer supports trivial (no-arg) initializers in its subtypes, as well as variable-length arugmented and keyword argument initializers. I recommend always using this form as it doesn't impose syntax in the simplest (trivial constructor) case but allows for the more complex functionality without imposing maintenance.