Did you ever have to write an initializer whose body consisted of little more than a suite of self.attr = attr style assignments? Here's a utility function that factors out this task.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
def attributesFromDict(d, obj=None, objName="self"): if obj is None: obj = d.pop(objName) for n, v in d.iteritems(): setattr(obj, n, v) class Before: def __init__(self, foo, bar, baz, boom=1, bang=2): self.foo = foo self.bar = bar self.baz = baz self.boom = boom self.bang = bang class After: def __init__(self, foo, bar, baz, boom=1, bang=2): attributesFromDict(locals())
As there is no additional logic in After.__init__(), the locals() dictionary contains only the parameters provided. attributesFromDict() by default extracts self and interprets all other items in the dictionary as attribute name/value pairs which are then set. This is similar to the technique of using only keyword parameters
def __init__(self, **kw): self.__dict__.update(kw)
but the latter lacks an easy way to specify the mandatory/optional parameters and has often proved a showstopper when reading other people's code.
Limitations: As there is no easy way to specify a subset of the local variables, you cannot conveniently use attributesFromDict() in a method with complex logic that needs temporary variables. For the same reason it is not easily applicable in a subclass, that propagates a subset of its parameters to the baseclass initializer.
Credits: John J. Lee originally posted the problem on comp.lang.python, and if you are interested in the strange detours that led to the solution presented above, have a look at http://mail.python.org/pipermail/python-list/2004-April/216871.html