[Tutor] dynamic argument lists

Kent Johnson kent37 at tds.net
Sat Aug 30 13:59:27 CEST 2008


On Sat, Aug 30, 2008 at 5:09 AM, eShopping
<etrade.griffiths at dsl.pipex.com> wrote:
> I don't understand the difference between
>
> myfunc (**kwargs)
>
> and
>
> myfunc (kwargs)
>
> Would someone mind explaining this?  I never managed to find a satisfactory
> explanation for what "**" means!

One is a function that takes keyword args, with the keyword args being
passed in a dict; the other is a function that just takes a dict as an
argument.

For example, here f() is a function of a single argument.:

In [18]: def f(x):
   ....:     print x

The argument can be a string:

In [19]: f('foo')
foo

Or a dict:
In [20]: d=dict(a=1, b=2)

In [21]: f(d)
{'a': 1, 'b': 2}

f() doesn't take keyword arguments:

In [27]: f(a=1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/Users/kent/<ipython console> in <module>()

TypeError: f() got an unexpected keyword argument 'a'

The ** notation means, pass the key/value pairs of the dict as keyword
args. Since f() doesn't accept keyword args, it fails the same way as
an explicit keyword:

In [22]: f(**d)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/Users/kent/<ipython console> in <module>()

TypeError: f() got an unexpected keyword argument 'a'


Here is a function that takes keyword args:

In [23]: def g(a=None, b=None):
   ....:     print a, b

In [24]: g('foo')
foo None

Passing the dict without ** treats it as an ordinary argument. Here
the parameter 'a' is set to the dict; 'b' is None:

In [25]: g(d)
{'a': 1, 'b': 2} None

Using the ** syntax assigns the key/value pairs of the dict to the
keyword args of the function:

In [26]: g(**d)
1 2

The names of the keywords are still checked:

In [28]: d['c'] = 3

In [29]: g(**d)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/Users/kent/<ipython console> in <module>()

TypeError: g() got an unexpected keyword argument 'c'


You can define a function that accepts any keywords. This is the flip
side of passing keywords in a dict; the function receives a dict
containing the keywords:

In [30]: def h(**kwargs):
   ....:     print kwargs

This particular function takes *only* keyword arguments:

In [31]: h(1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/Users/kent/<ipython console> in <module>()

TypeError: h() takes exactly 0 arguments (1 given)

It accepts any keyword arguments. They appear in a dict named kwargs:
In [32]: h(a=1, b=2)
{'a': 1, 'b': 2}

Passing a dict directly doesnt' work:

In [33]: h(d)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/Users/kent/<ipython console> in <module>()

TypeError: h() takes exactly 0 arguments (1 given)

Using the ** syntax in the call works:
In [34]: h(**d)
{'a': 1, 'c': 3, 'b': 2}


There is also a similar * syntax for positional paramaters, and you
can use any combination of named positional, named keyword, * and **
args in the same function. See
http://docs.python.org/tut/node6.html#SECTION006700000000000000000
http://docs.python.org/ref/function.html
http://docs.python.org/ref/calls.html#calls

for more.

Kent


More information about the Tutor mailing list