The mysterious miss args and mister kwargs
Posted on October 8th, 2009
In this piece, I explain a bit about args and kwargs and how they can be used in your python scripts.
As usual, when you start learning a new programming language, you skip some learning to jump directly into coding. Myself, I skipped the part about positional and keywords argument and first starting coding python and I was a bit mystified at first by those *args and **kargs I was seeing everywhere!
So here's a little demystification of those two.
Miss *args
So, *args (or whatever other name) is a tuple that contains the positional argument of a function.
1 2 3 4 5 | >>> def foo(*args):
... print args
...
>>> foo('arg1', 'arg2')
('arg1', 'arg2')
|
As you can see, args is a tuple containing the arguments. This can be pretty usefull is you want to have variable length argument list. This being said, you have to know that you can use this the other way around!
1 2 3 4 5 | >>> def foo(arg1, arg2):
... print arg1, arg2
...
>>> foo(*('arg1', 'arg2'))
arg1 arg2
|
Here, you call the function foo giving it a tuple containing the positional arguments and they are assigned in order to arg1, arg2.
Mister **kwargs
Interestingly, you could also have used **kwargs to do the previous function call. This is because **kwargs is a dictionnary of named arguments. So to execute the previous exemple, you would have done:
1 2 | >>> foo(**{'arg1':'first_arg','arg2':'second_arg'})
first_arg second_arg
|
Here's how to used named arguments in your function:
1 2 3 4 5 | >>> def foo(**kwargs):
... print kwargs
...
>>> foo(a=1, b=2, c=3)
{'a': 1, 'c': 3, 'b': 2}
|
As you can see, here, python just passed your named arguments as a dictionary to your function.
putting it all together
You can use formal parameters, *args and **kwargs at the same time. You just have to keep in mind that they are evaluated in that order. So:
1 2 3 4 5 | >>> def foo(a, b, *args, **kwargs):
... print a, b, args, kwargs
...
>>> foo(1, *(2,3,4), **{'5':5})
1 2 (3, 4) {'5': 5}
|
Finally, you can call function using this syntax as you see fit:
1 2 3 4 5 | >>> def foo(a,d):
... print a,b,c,d
...
>>> foo(1,*(2,),**{'c':3, 'd':4})
1 2 3 4
|
what's the point?
So what's point of all this? Well, I was there scratching my head needing to call a function with a named argument but having only the string representing that name. I was considering using eval to work around this problem until I realised how easy it was with the ** syntax!
1 2 | argument_name = 'some_argument_name'
result = the_function(**{argument_name:value})
|
God thanks Dive Into Python to explain those simple yet essential things!
