arguments to functions

Bengt Richter bokr at oz.net
Sun Jun 30 20:37:04 CEST 2002


On Sun, 30 Jun 2002 18:52:10 -0700, Uwe Mayer <merkosh at hadiko.de> wrote:

>hi,
>
>I wanted to pass one named and a collection of unnamed (an arbitrary 
>number) to a function:
>
>def test(expected=None, *misc):
>    print(expected)
>    print(misc)
>
>Now, unluckyly 'test' interprets the first unnamed parameter to test as 
>the value for 'expected':
>
>test(5, expected=10)
>TypeError: test() got multiple values for keyword argument 'expected'
>
>on the other side any keyword arguments must follow non-keyword 
>arguments:
>
>test(expected=5, 10)
>SyntaxError: non-keyword arg after keyword arg
>
>Which is a pitty, because I think this version is clear.
>
>Is that *it*, or am I doing something wrong here?
>
There is something wrong. If you want to call with keyword args, you have to provide
a keyword dict arg (a name at the end of the arg list prefixed with **) for receiving
them, and you didn't.

I think the multiple values message is misleading, though, since keywords
are in a separate name space (a dict parameter), and I don't see why you
couldn't have equivalent names (other than implementation inconvenience)
to those in the named parameter list. In fact, it could be convenient
for implementing selective override of defaults.

Nut not only is the error message misleading, it's the message is generated
before checking whether _any_ keyword arguments _at all_ are allowed.
Note what happens with another kw name:

 >>> test(10, other=5)
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 TypeError: test() got an unexpected keyword argument 'other'
                          ^^^^^^^^^^

Which shows the real error in the call. You could fix that part:
 >>> def test(expected=None, *misc, **kwargs):
 ...     print expected
 ...     print misc
 ...     print kwargs
 ...
 >>> test(10, 11, 12, other=5)
 10
 (11, 12)
 {'other': 5}

But unfortunately, it still won't let you use 'expected' as keyword for kwargs:

 >>> test(10, 11, 12, expected=5)
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 TypeError: test() got multiple values for keyword argument 'expected'

I'd be inclined to call that a bug, actually.

You could get what I guess is the effect you want (keyword value takes priority) something like:

 >>> def test(_expected=None, *misc, **kwargs):
 ...     expected = kwargs.get('expected',None) or _expected
 ...     print 'expected:%s, misc:%s, kwargs:%s' % (`expected`,`misc`,`kwargs`)
 ...
 >>> test()
 expected:None, misc:(), kwargs:{}
 >>> test(10)
 expected:10, misc:(), kwargs:{}
 >>> test(10, expected=5)
 expected:5, misc:(), kwargs:{'expected': 5}
 >>> test(expected=5)
 expected:5, misc:(), kwargs:{'expected': 5}
 >>> test(10, 11, 12, expected=5)
 expected:5, misc:(11, 12), kwargs:{'expected': 5}
 >>> test(10, 11, 12)
 expected:10, misc:(11, 12), kwargs:{}

 >>> test(10, other=5)
 expected:10, misc:(), kwargs:{'other': 5}

If you want to check first that kwargs is either empty or has only
'expected' as a key, that's easy too.

Regards,
Bengt Richter



More information about the Python-list mailing list