More Python — keyword arguments

Hey, I almost forgot one of my favorite shared features between Common Lisp and Python: keyword arguments! A lot of my research code tends to have lots of parameters, especially in object initialization, but often elsewhere too, like in functions for displaying internal state or writing out data, where I’ll have parameters that usually take default values, but occasionally need to be changed. Languages like C/C++/Java allow optional arguments, but you still have to remember the order, and if you want a non-default the 8th optional argument, you have to give values to the 7 args before it in the argument list. This makes for crazy unreadable code, like this:

x = Foo(0,NULL,NULL,NULL,5,0,0,0,NULL,NULL,32);

I don’t know how I’d come back to this code and 6 months and understand what’s going on.

Lisp and Python’s keyword arguments are a great solution for this problem. They allow you to use the parameter name in the function call. In lisp you might write the function definition like this (assuming short variable names for brevity here):

(defun foo (&key (a 0) b c d (e 0) (f 0) (g 0) h i (j 0))
;; keyword args default to nil, unless another default is
;; specified, as with a, e, f, g, and j.
...)

Then call it like this:

(setq x (foo :e 5 :j 32))

Here all the unspecified parameters get their defaults. Also the parameters can be specified in any order.

Python’s keyword args work basically the same way, but they’re arguably even more powerful. In Python we’d do this:

def foo(a=0, b=None, c=None, d=None, e=0, f=0, g=0,
h=None, i=None, j=0):
...

and call it like this:

x = foo(e=5, j=32)

Again, the keyword arguments can be given in any order. You gotta admit this is much more readable than the C++/Java way. The interesting thing is that Python implements keyword args with dictionaries, a primitive data type. They expose that to the programmer, so you can pass a dictionary where you would put keyword arguments:

dict = {'e':5, 'j':32}
x = foo(**dict)

You can even mix-n-match:

dict = { 'j':32 }
x = foo(e=5,**dict)

You can also use a dictionary to hold a variable number of keyword arguments in the function definition, but I won’t go into that here. Anyway, this was a feature of Common Lisp I didn’t think I could give up. Scheme has them as an added syntax in a library, but they don’t seem to be a generally accepted part of the scheme programming paradigm like they are in Python

Advertisements
Posted in Python. 4 Comments »

4 Responses to “More Python — keyword arguments”

  1. vatsalad Says:

    I just want to confirm my understanding – is None in python equivalent to the “null” keyword in other languages? is that right?

  2. Kumaresan Says:

    def myFunc(arg1, arg2, *arg3, **arg4):
    print ‘Arg1: %s’ % arg1
    print ‘Arg2: %s’ % arg2
    print ‘Arg3: %s’ % arg3
    print ‘Arg4: %s’ % arg4

    inputDict = {‘arg1′:’A1’, ‘arg2′:’A2’, ‘arg3’=[‘V1′,’V2′],’arg4’:{‘KV1′:’VAL’}
    myFunc(**inputDict)

    So this method accepts **kwArgs only. How do I assign Input to variable arg *arg3?

    • Jefferson Says:

      The function (it’s not a method unless it’s part of a class), does not accept keywords only. Arg1 and arg2 are positional args. Arg3 contains the variable-length list of any more positional args beyond arg2. Arg4 contains the keyword arguments. Some examples would probably help.

      I changed your function slightly to make printing empty arguments easier:

      def myFunc(arg1, arg2, *arg3, **arg4):
      print 'Arg1', arg1
      print 'Arg2', arg2
      print 'Arg3', arg3
      print 'Arg4', arg4

      Now here are some interactions:

      In [22]: myFunc(1,2,x=3,y=4)
      myFunc(1,2,x=3,y=4)
      Arg1 1
      Arg2 2
      Arg3 ()
      Arg4 {'y': 4, 'x': 3}

      In [23]: myFunc(1,2,3,4,5,x=3,y=4)
      myFunc(1,2,3,4,5,x=3,y=4)
      Arg1 1
      Arg2 2
      Arg3 (3, 4, 5)
      Arg4 {'y': 4, 'x': 3}

      In [24]: myFunc(1,2,*[3,4,5],x=3,y=4)
      myFunc(1,2,*[3,4,5],x=3,y=4)
      Arg1 1
      Arg2 2
      Arg3 (3, 4, 5)
      Arg4 {'y': 4, 'x': 3}

      In [25]: myFunc(*[1,2,3,4,5],x=3,y=4)
      myFunc(*[1,2,3,4,5],x=3,y=4)
      Arg1 1
      Arg2 2
      Arg3 (3, 4, 5)
      Arg4 {'y': 4, 'x': 3}

      In [26]: myFunc(*[1,2,3,4,5],**{'x':10, 'y':20})
      myFunc(*[1,2,3,4,5],**{'x':10, 'y':20})
      Arg1 1
      Arg2 2
      Arg3 (3, 4, 5)
      Arg4 {'y': 20, 'x': 10}

      In [27]: myFunc(x=1,y=2)
      myFunc(x=1,y=2)
      ---------------------------------------------------------------------------
      TypeError Traceback (most recent call last)

      /Users/jprovost/workspace/dm.fraud/scratch/ in ()

      TypeError: myFunc() takes at least 2 non-keyword arguments (0 given)


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: