|
|
 |
|
Title: Clean up __init__() methods that contain only attribute assignments.
Submitter: Peter Otten
(other recipes)
Last Updated: 2004/04/27
Version no: 1.0
Category:
Shortcuts
|
|
3 vote(s)
|
|
|
|
Description:
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.
Source: Text Source
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())
Discussion:
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
|
|
Add comment
|
|
Number of comments: 2
A more robust approach?, Gary Robinson, 2004/04/28
The following version works even in __init__ methods which have other logic and temporary variables:
def assignAttr(obj, dctLocals):
codeObject = obj.__class__.__init__.im_func.func_code
tupNames = codeObject.co_varnames[1:codeObject.co_argcount]
for strName in tupNames:
obj.__dict__[strName] = dctLocals[strName]
class After:
def __init__(self, foo, bar, baz, boom=1, bang=2):
assignAttr(self, locals())
Add comment
a simplification (no parameter needed), Alain Pointdexter, 2006/09/01
import inspect
def init_attributes():
......d=inspect.currentframe().f_back.f_locals
......obj = d.pop("self")
......for n, v in d.iteritems():
............setattr(obj, n, v)
class After:
......def __init__(self, foo, bar, baz, boom=4, bang=5):
...........init_attributes()
Add comment
|
|
|
|
|
 |
|