[Tutor] Need better understanding of **kwargs

wesley chun wescpy at gmail.com
Sun Jun 7 07:10:10 CEST 2009


>> Hello, I thought I understood **kwargs until I stumbled with this
>> function:
>>
>> def changeflexion(myword, mytag, **dicty):
>>        :
>>
>> but when I import the module and call:
>> a = conjugate.changeflexion('estaban', 'VLFin', conjugate.mydict)
>> I get this error:
>> TypeError: changeflexion() takes exactly 2 arguments (3 given)
>> Isn't the 3rd argument supposed to be a dictionary?
>
> No, **dicty means the function takes zero or more keyword parameters:
>
>>>> def f(a,b,**k):
>
> ...  print a,b,k
> ...
>>>>
>>>> f(1,2) # no keyword parameters
>
> 1 2 {}
>>>>
>>>> f(1,2,c=3) # one keyword parameter
>
> 1 2 {'c': 3}
>>>>
>>>> f(1,2,{'c':3}) # a dictionary
>
> Traceback (most recent call last):
>  File "<interactive input>", line 1, in <module>
> TypeError: f() takes exactly 2 arguments (3 given)
>
> But there is a syntax to pass keyword arguments as a dictionary:
>
>>>> f(1,2,**{'c':3})
>
> 1 2 {'c': 3}


bob and mark are both correct, in their own special way. :-) what they
really meant to say is something like this:

1. if your entire purpose of the function is to accept a dictionary of
values and process them like you do in your function, there's no need
to make it a kwargs dict. as bob suggested, you can just remove the
"**" and keep the rest as-is.

2. however, if you're calling the function where there are a variable
number of keyword arguments, like mark's example:

f('foo', 20, c=3, d=4, g='bar')
f('boo', -10, e=2.718, pi=3.14)
f('one', 'two', d=-40, e=2.718)

...where both the number of arguments may vary, or if the names may
vary, i.e., (c,d,g) vs. (e, pi) vs. (d, e), etc., then this is more of
a correct use case for a **kwargs variable. it's whole purpose is for
keyword arguments and not necessarily a mechanism to pass a dictionary
to a function even though you can do it.

one exception is when you're trying to cascade a kwargs dictionary to
begin with, IOW, you're trying to continue to pass it on to yet
another function:

def f1(...., **kwargs):
    :

def f2(...., **kwargs):
    :
    if 'bar' not in kwargs:        # add another value to kwargs
        kwargs['bar'] = 'foo'
        rv = f1(..., **kwargs)     # process by passing to f1()

hope this helps!
-- wesley
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"Core Python Programming", Prentice Hall, (c)2007,2001
"Python Fundamentals", Prentice Hall, (c)2009
    http://corepython.com

wesley.j.chun :: wescpy-at-gmail.com
python training and technical consulting
cyberweb.consulting : silicon valley, ca
http://cyberwebconsulting.com


More information about the Tutor mailing list