ASPN ActiveState Programmer Network  
ActiveState, a division of Sophos
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups
Submit Recipe
My Recipes

All Recipes
All Cookbooks


View by Category

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

 

4 stars 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



Highest rated recipes:

1. A simple XML-RPC server

2. Web service accessible ...

3. Wrapping template engine ...

4. Assignment in expression

5. SOLVING THE METACLASS ...

6. Povray for python

7. Calling Windows API ...

8. Generic filter logic ...

9. Function Decorators by ...

10. MS SQL Server log monitor




Privacy Policy | Email Opt-out | Feedback | Syndication
© 2006 ActiveState Software Inc. All rights reserved.