I sometimes do this for classes that act "bunch-like", that is, they have a bunch of customizable attributes:
class SuperClass(object):
def __init__(self, **kw):
for name, value in kw.iteritems():
if not hasattr(self, name):
raise TypeError('Unexpected argument: %s' % name)
setattr(self, name, value)
class SubClass(SuperClass):
instance_var = None # default value
class SubClass2(SubClass):
other_instance_var = True
@property
def something_dynamic(self):
return self._internal_var
@something_dynamic.setter # new Python 2.6 feature of properties
def something_dynamic(self, value):
assert value is None or isinstance(value, str)
self._internal_var = value
Then you can call SubClass2(instance_var=[], other_instance_var=False)
and it'll work without defining __init__
in either of them. You can use any property as well. Though this allows you to overwrite methods, which you probably wouldn't intend (as they return True for hasattr()
just like an instance variable).
If you add any property
or other other descriptor it will work fine. You can use that to do type checking; unlike type checking in __init__
it'll be applied any time that value is updated. Note you can't use any positional arguments for these unless you override __init__
, so sometimes what would be a natural positional argument won't work. formencode.declarative covers this and other issues, probably with a thoroughness I would not suggest you attempt (in retrospect I don't think it's worth it).
Note that any recipe that uses self.__dict__
won't respect properties and descriptors, and if you use those together you'll just get weird and unexpected results. I only recommend using setattr()
to set attributes, never self.__dict__
.
Also this recipe doesn't give a very helpful signature, while some of the ones that do frame and function introspection do. With some work it is possible to dynamically generate a __doc__
that clarifies the arguments... but again I'm not sure the payoff is worth the addition of more moving parts.