ActiveState Code

Recipe 410665: Automatically set all passed parameters to self


I have found it tedious to, when passing many variables to a class's constructor, assigning them all to self. This is a method to assign them automatically. It works with default arguments as well.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#The old way:
class Old:
    def __init__(self, a, b, c, d, e, f, g, h, i=200, j=100):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
        self.f = f
        self.g = g
        self.h = h
        self.i = i
        self.j = j


#The new way:

def setargstoself(inst, params):
    code = inst.__init__.func_code
    for item in code.co_varnames[1:code.co_argcount]:
        setattr(inst, item, params[item])

class FooBar:
    def __init__(self, a, b, c, d, e, f, g, h, i=200, j=100)
        setargstoself(self, locals())

fb = FooBar(*range(9)) #set i, leave j as default


#An alternative implementation for functions with arguments *x or **y.
#However, this is less useful, because it would just be another 2 lines to
#assign each one of those to self.
#Here it is if anyone is interested.

import inspect

def setargstoself2(inst, params):
    formal_args, var_args, kwd_args, unused = inspect.getargspec(inst.__init__)
    for item in formal_args:
        if item != 'self':
            setattr(inst, item, params[item])
    if var_args:
        setattr(inst, var_args, params[var_args])
    if kwd_args:
        setattr(inst, kwd_args, params[kwd_args])

class FooBar2:
    def __init__(self, a, b, c, *x, **y):
        setargstoself2(self, locals())

fb2 = FooBar2(name='chloe', name2 = 'sam', *range(6))

Comments

  1. 1. At 3:44 a.m. on 25 apr 2005, Sakesun Roykiattisak said:

    Can stack inspection make it simpler ? Honestly, I have no plan to use this recipe. But the trick is very educative to me. Sure I'll visit this recipe again in the future.

    BTW, I wonder if stack-related functions in the module inspect can make it even simpler. Just like how the zope.interface.implements works. Can we avoid all parameters to the function at all ? Wish someone give me an insight

  2. 2. At 5:14 a.m. on 25 apr 2005, Michael Chermside said:

    What's wrong with the simple approach? What's wrong with this solution:

    class FooBar:
        def __init__(self, a,b,c,d,e,f,g,h, i=100, j=100):
            self.__dict__.update(locals())
    

    It has the advantage of NOT requiring any strange playing about with func_code and co_varnames. It's a trivial one-liner. It doesn't require creating a "setargstoself" function that needs to be imported (or repeated in every module). The only disadvantage is that it sets "self" to, well, self. If this is too painful, you can use a second line to delete that (but why bother... Python's GC can handle reference loops quite easily these days).

  3. 3. At 5:28 a.m. on 25 apr 2005, Christopher Smith said:

    Educational, yes... ...but does it cut against the "explicit is better than implicit" ethic of python?

    Maybe it's a C++-ism, but I actually like to lay out all those crazy variables in the __init__, and document them...

  4. 4. At 6:24 a.m. on 25 apr 2005, Peter Bengtsson said:

    Debugging. I think it a great recipe because it can be used to debug how a __init__ method is called.

  5. 5. At 2:41 p.m. on 4 jul 2005, Chris Arndt said:

    Another variant.

    class Foo:
        def __init__(self, a, b, c, spamm=True, eggs=False):
            [setattr(self, a, v) for a,v in locals.items() if a != 'self']
    
  6. 6. At 2:56 p.m. on 4 jul 2005, Chris Arndt said:

    arrrgh! Sorry, the code from the above comment had a typo and would have introduced also another variable into the namespace (from the unassigned return value of the list comprehension).

    So, baby, one more time:

    class Foo:
        def __init__(self, a, b, c, spamm=True, eggs=False):
            for a,v in locals().items():
                if a != 'self':
                    setattr(self, a, v)
    
  7. 7. At 6:35 p.m. on 7 oct 2008, David Lambert said:

    I use inheritance and the doc string to avoid writing __init__ methods.

    class HiddenArguments:
    
        def __init__(self,**kwargs):
            self.__dict__.update(kwargs)
            # could save the kwargs dictionary
    
        #def __repr__(self):
        #    '''
        #        could use kwargs in a default representation method,
        #        perhaps 'memo'ized.
        #    '''
        #    return '%s(%s)'%(self.__class__.__name__,'\n'.join(clever iterator))
    
    
    
    class C(HiddenArguments):
    
        '''
            construct a C object using
    
            C(
                a:'description of a',
                b:'b described',
                ...
                )
        '''
    
        def method(self,...):
            #use self.a etceteras
    

Sign in to comment