FAQ
Is there a nice Python idiom for constructors which would expedite the
following?

class Foo:
def __init__(self, a,b,c,d,...):
self.a = a
self.b = b
self.c = c
self.d = d
...

I would like to keep the __init__ parameter list explicit, as is,
rather than passing in a dictionary, as I want the code to be explicit
about what arguments it expects... in effect enforcing the right number
of arguments.

Search Discussions

  • Chris Green at Jun 1, 2005 at 6:17 pm

    "Mac" <idontneednostinkinid at yahoo.com> writes:

    Is there a nice Python idiom for constructors which would expedite the
    following?

    class Foo:
    def __init__(self, a,b,c,d,...):
    self.a = a
    ...
    You could try:

    class Foo:
    def __init__(self,a,b,c,d):
    args = locals()
    for arg in args.keys():
    if name!='self':
    self.__dict__[arg] = args[arg]

    I don't think it saves you a whole lot of typing (and gains you a lot
    of ugly complexity). I find as soon as I do this, I then want to
    manipulate a,b,c,d .

    You might look to see if you can customize your editor to use
    templates/interaction and then inserts the right text for you.
    --
    Chris Green <cmgreen at uab.edu>
    "Yeah, but you're taking the universe out of context."
  • Mac at Jun 1, 2005 at 7:26 pm

    You might look to see if you can customize your editor to use
    templates/interaction and then inserts the right text for you.
    Well, I'm not really concerned with "amount of typing" as much as with
    the inherent ugliness, tediousness, and lack of elegance of the
    original form. Alas, templates/macros would not fix the latter.
  • Laszlo Zsolt Nagy at Jun 1, 2005 at 8:11 pm

    You could try:

    class Foo:
    def __init__(self,a,b,c,d):
    args = locals()
    for arg in args.keys():
    if name!='self':
    self.__dict__[arg] = args[arg]
    Should be:

    if arg!='self'

    Also it is not perfect. For example:

    class Foo:
    def __init__(self,a,b,c,d):
    temp = 12
    self.foo2 = temp + 4
    args = locals()
    for arg in args.keys():
    if arg!='self':
    self.__dict__[arg] = args[arg]

    a = Foo(1,2,3,4)
    print dir(a)

    Results in:

    ['__doc__', '__init__', '__module__', 'a', 'b', 'c', 'd', 'foo2', 'temp']

    E.g. not only the parameters but all local variables are used...
  • Laszlo Zsolt Nagy at Jun 1, 2005 at 7:29 pm

    Mac wrote:
    Is there a nice Python idiom for constructors which would expedite the
    following?

    class Foo:
    def __init__(self, a,b,c,d,...):
    self.a = a
    self.b = b
    self.c = c
    self.d = d
    ...

    I would like to keep the __init__ parameter list explicit, as is,
    rather than passing in a dictionary, as I want the code to be explicit
    about what arguments it expects... in effect enforcing the right number
    of arguments.
    I could list the parameter names programatically:

    class A(object):
    def __init__(self,a,b,c,d,e,f,):
    varnames = self.__init__.im_func.func_code.co_varnames
    for varname in varnames[1:7]:
    print varname

    a = A(1,2,3,4,5,6)

    But I could not get their values.
  • Steven Bethard at Jun 1, 2005 at 8:33 pm

    Mac wrote:
    Is there a nice Python idiom for constructors which would expedite the
    following?

    class Foo:
    def __init__(self, a,b,c,d,...):
    self.a = a
    self.b = b
    self.c = c
    self.d = d
    ...
    py> class Foo(object):
    ... def __init__(self, a, b, c, d):
    ... params = locals()
    ... del params['self']
    ... self.__dict__.update(params)
    ...
    py> vars(Foo(1, 2, 3, 4))
    {'a': 1, 'c': 3, 'b': 2, 'd': 4}

    Just make sure that "params = locals()" is the first line in __init__
    method. (Otherwise you might have other local variables slip in there.)

    I wouldn't actually advise this code to anyone though. I find that if I
    have more than 3 or 4 parameters to a function, I should probably
    refactor my code. And with 4 or fewer parameters, I don't think you
    gain any clarity by using the "self.__dict__.update" trick.

    STeVe
  • Peter Dembinski at Jun 4, 2005 at 9:52 am

    Steven Bethard <steven.bethard at gmail.com> writes:

    Mac wrote:
    Is there a nice Python idiom for constructors which would expedite
    the following?
    class Foo:
    def __init__(self, a,b,c,d,...):
    self.a = a
    self.b = b
    self.c = c
    self.d = d
    ...
    py> class Foo(object):
    ... def __init__(self, a, b, c, d):
    ... params = locals()
    ... del params['self']
    ... self.__dict__.update(params)
    ...
    py> vars(Foo(1, 2, 3, 4))
    {'a': 1, 'c': 3, 'b': 2, 'd': 4}

    Just make sure that "params = locals()" is the first line in
    __init__ method. (Otherwise you might have other local variables
    slip in there.)
    Or write it like this, using Python's dynamic code execution:

    #v+

    class A:
    def __init__(self, a, b, c, d):
    initial = {'a' : 1, 'b' : 2, 'c' : 3, 'd' : 4}

    for param in initial.keys():
    exec "self.%s = initial['%s']" % (param, param)

    #v-
  • Peter Dembinski at Jun 4, 2005 at 10:05 am
    Peter Dembinski <pdemb at gazeta.pl> writes:

    [snap]

    Eh, sorry, it should look like this:
    #v+

    class A:
    def __init__(self, a, b, c, d):
    initial = {'a' : 1, 'b' : 2, 'c' : 3, 'd' : 4}
    initial = {'a' : a, 'b' : b, 'c' : c, 'd' : d}
    for param in initial.keys():
    exec "self.%s = initial['%s']" % (param, param)

    #v-
  • Steven Bethard at Jun 4, 2005 at 3:49 pm

    Peter Dembinski wrote:
    class A:
    def __init__(self, a, b, c, d):
    initial = {'a' : a, 'b' : b, 'c' : c, 'd' : d}
    for param in initial.keys():
    exec "self.%s = initial['%s']" % (param, param)
    This is not a good use case for exec. Use setattr:

    for param in initial:
    setattr(self, param, initial[param])

    Or better yet, just update the instance dict:

    self.__dict__.update(initial)

    But this misses the OP's point. The issues was that the OP didn't want
    to write a, b, c and d again. Not only does this proposal make you
    write them again, it makes you write them again twice!

    STeVe
  • Peter Dembinski at Jun 4, 2005 at 4:18 pm
    Steven Bethard <steven.bethard at gmail.com> writes:

    Peter Dembinski wrote:
    class A:
    def __init__(self, a, b, c, d):
    initial = {'a' : a, 'b' : b, 'c' : c, 'd' : d}
    for param in initial.keys():
    exec "self.%s = initial['%s']" % (param, param)
    This is not a good use case for exec. Use setattr: OK, true.
    From the other side: what are the usual uses of 'exec'?
  • Volker Grabsch at Jun 4, 2005 at 6:19 pm

    Peter Dembinski wrote:
    This is not a good use case for exec. Use setattr:
    OK, true.
    From the other side: what are the usual uses of 'exec'?
    An interactive Python interpreter. :-)

    No, seriously: Introspection is always better than exec.
    It is far less error phrone, especially because you don't need
    to deal with quoting issues, and because you have an initial
    syntax check of your Python code which is bypassed when using exec.

    Similarly, try to avoid system() whenever possible.


    Greets,

    --
    Volker Grabsch
    ---<<(())>>---
    \frac{\left|\vartheta_0\times\{\ell,\kappa\in\Re\}\right|}{\sqrt
    [G]{-\Gamma(\alpha)\cdot\mathcal{B}^{\left[\oint\!c_\hbar\right]}}}
  • Steven Bethard at Jun 4, 2005 at 9:29 pm

    Peter Dembinski wrote:
    From the other side: what are the usual uses of 'exec'?
    I have to say, I have yet to find a use for it.

    My intuition is that the good use cases for 'exec' have something to do
    with writing programs that allow users to interactively script the
    program actions. But I've never written such a program, so I can't
    speak much about it.

    STeVe
  • Terry Hancock at Jun 1, 2005 at 9:07 pm

    On Wednesday 01 June 2005 12:50 pm, Mac wrote:
    Is there a nice Python idiom for constructors which would expedite the
    following?

    class Foo:
    def __init__(self, a,b,c,d,...):
    self.a = a
    self.b = b
    self.c = c
    self.d = d
    ...

    I would like to keep the __init__ parameter list explicit, as is,
    rather than passing in a dictionary, as I want the code to be explicit
    about what arguments it expects... in effect enforcing the right number
    of arguments.
    Well, it's hard to automate it and keep the parameter list explicit,
    but you could do this, of course:

    class Foo:
    def __init__(self, *args):
    maps = zip(('a','b','c','d'), args[:4])
    for map in maps:
    setattr(self, map[0], map[1])

    Which *will* limit the arguments to the ones specified. As an additional
    tweak, you could make this a base class and put the argument list in
    the subclass to hide the magic:

    class Args:
    argspec = ()
    def __init__(self, *args):
    maps = zip(self.argspec, args[:len(self.argspec)])
    for map in maps:
    setattr(self, map[0], map[1])

    class Foo(Args):
    argspec = ('a', 'b', 'c', 'd')

    Or even better, use a method, so you can customize:

    class Args:
    argspec = ()
    def _get_args(self, *args):
    maps = zip(self.argspec, args[:len(self.argspec)])
    for map in maps:
    setattr(self, map[0], map[1])

    class Foo(Args):
    argspec = ('a', 'b', 'c', 'd')
    def __init__(self, *args):
    self._get_args(*args)

    This version silently ignores extra arguments, but you might
    want to raise an exception instead:

    class Args:
    argspec = ()
    def _get_args(self, *args):
    expected = len(self.argspec)
    given = len(args)
    if expected != given:
    raise TypeError("__init__ takes exactly %d arguments (%d given)" % (expected, given))
    maps = zip(self.argspec, args[:expected])
    for map in maps:
    setattr(self, map[0], map[1])

    Using this, I get the following response to too many arguments:
    g = Foo(1, '3', 4.0, 'spam', 'eggs') Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    File "<stdin>", line 4, in __init__
    File "<stdin>", line 7, in _get_args
    TypeError: __init__ takes exactly 4 arguments (5 given)

    HTH

    Cheers,
    Terry

    --
    Terry Hancock ( hancock at anansispaceworks.com )
    Anansi Spaceworks http://www.anansispaceworks.com
  • Terry Reedy at Jun 1, 2005 at 9:44 pm
    "Mac" <idontneednostinkinid at yahoo.com> wrote in message
    news:1117648259.190124.76800 at f14g2000cwb.googlegroups.com...
    Is there a nice Python idiom for constructors which would expedite the
    following?

    class Foo:
    def __init__(self, a,b,c,d,...):
    self.a = a
    self.b = b
    self.c = c
    self.d = d
    Do you like this better?

    self.a, self.b, self.c, self.d = a,b,c,d

    For my own code, I might use 's' instead of 'self' to save typing...

    Terry J. Reedy
  • Mac at Jun 1, 2005 at 10:24 pm
    This was the direction I was aiming for initially, and I have used this
    form before, but was hoping there was a way I could go one step
    further, and somehow get rid of the repetition of "self."... Heh,
    ideally:

    self.{a,b,c,d} = a,b,c,d

    Alas, not Python syntax... :)

    I do like Steven's form of a solution, and I think I'll give it a spin
    for the really ugly spots (refactoring is too expensive right now;
    prototype-code).
  • Tracyshaun at Jun 6, 2005 at 6:32 pm
    How about just doing this:

    class Foo(object):
    __slots__ = ('a','b','c','d')
    def __init__(self, *args):
    for (name, arg) in zip(self.__slots__, args):
    setattr(self, name, arg)

    --T
  • Tracyshaun at Jun 6, 2005 at 6:38 pm
    And you probably should add:

    ...
    def __init__(self, *args):
    assert len(args) == len(self.__slots__)
    ...

    --T

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedJun 1, '05 at 5:50p
activeJun 6, '05 at 6:38p
posts17
users9
websitepython.org

People

Translate

site design / logo © 2022 Grokbase