idiom for constructor?

Terry Hancock hancock at anansispaceworks.com
Wed Jun 1 17:07:15 EDT 2005


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




More information about the Python-list mailing list