Tags

This post by Eliot at Salty Crane gives a nice introduction to how to work with *args and **kwargs in Python. Here we expand on the use of **kwargs, exploring a variety of its behaviors.

I know all of this to work only with Python 3.2.2, but assume that it works with other Python 3.x versions, and maybe Python 2.x versions.

This first example is just a restatement of Elliot’s last example. Let’s say we have a function:

def foo(a, b, c):
   print("a = " + str(a))
   print("b = " + str(b))
   print("c = " + str(c))

and we have:

x = {"a" : 1, "b" : 2, "c" : 3}
foo(**x)

then as expected we get:

a = 1
b = 2
c = 3

Now let’s say we have:

y = {"a" : 1, "b" : 2}
z = {"a" : 1, "c" : 3}
w = {"a" : 1, "b" : 2, "c" : 3, "d" : 4}
v = {"a" : 1, "b" : 2, "d" : 4}
u = {"a" : 1, "b" : 2, "d" : 4, "e" : 5}
foo(**y)
foo(**z)
foo(**w)
foo(**v)
foo(**u)

We’re missing “c” and “b” in the first two calls respectively and in both cases we get:

Traceback (most recent call last):
  File "", line 1, in
TypeError: foo() takes exactly 3 arguments (2 given)

As for the calls with “w” and “v” as input, for both we get:

Traceback (most recent call last):
  File "", line 1, in
TypeError: foo() got an unexpected keyword argument 'd'

So in this last case Python knows that “d” is not an argument to “foo” and reports it. Unfortunately for the first two cases it does not report which argument we are missing.

Finally for the last call, where we use “u” as the input we get:

Traceback (most recent call last):
  File "", line 1, in
TypeError: foo() got an unexpected keyword argument 'e'

Here Python reports an issue with “e”, but not with “d”. So it looks like Python simply bails when it detects the first problem.

This is all a bit unfortunate. When arguments are not present it would be nice to know which ones are missing. Similarly, when there are too many arguments given, it would be nice to know which ones those are. If we have missing arguments and bad arguments, it would be nice to know that both cases exist. This makes fixing your program much easier.

Happily by using the inspect module, and in particular the getfullargspec function, we can pretty easily write a wrapper that does the appropriate error checking and crafts an outstanding error message. Unfortunately, due to contractual issues, I must leave this as an exercise for the reader.

Advertisements