Welcome, guest | Sign In | My Account | Store | Cart

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, 51 lines
 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))

7 comments

Sakesun Roykiattisak 16 years, 7 months ago  # | flag

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

Michael Chermside 16 years, 7 months ago  # | flag

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).

Christopher Smith 16 years, 7 months ago  # | flag

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...

Peter Bengtsson 16 years, 7 months ago  # | flag

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

Chris Arndt 16 years, 4 months ago  # | flag

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']
Chris Arndt 16 years, 4 months ago  # | flag

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)
David Lambert 13 years, 1 month ago  # | flag

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
Created by nicksjacobson on Thu, 21 Apr 2005 (PSF)
Python recipes (4591)
nicksjacobson's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks