Python - *args and **kwargs

From frist touched python, I have met many differeces from Java.
Now, I want to indroduce a new thing I learnt yesterday – *args and **kwargs. In fact, there is no need to confuse about what args and kwargs mean, the names are just conventional. let’s focus our attention on * and **.

We may often see * and ** used as arguments in function definitions, but they have different meanings when used in function calls. In the former case, they perform a pack process, and in the latter case, they perform a unpack process.

In Function Definition

Common Definition

def foo(a, b):
    print a, b

This is a common function definition in python. When we call it, we need to pass exact 2 arguments to it. less or more parameter will cause error.

foo(1, 2)
# output
1 2

foo(1)
# output 
TypeError: foo() takes exactly 2 arguments (1 given)

Definition with args and kwargs

def foo(*args, **kwargs):
    print args, kwargs

When we use *args and **kwargs, we can pass an arbitrary number of arguments. The difference between them is that *args can accept a non-keyword arguments list, while **kwargs’ is a keyword arguments list.

We can regard args as tuple and kwargs as dictionary.

foo()
# output
() {}

foo(1, 2, 3, a=1, b=2, c=3)
# output
(1, 2, 3) {'a': 1, 'c': 3, 'b': 2}

foo(1, 2, 3, a=1, b=2, c=3, 4, 5, 6)
# output
SyntaxError: non-keyword arg after keyword arg

When we pass an arbitrary number of non-keyword arguments, * packs them as a tuple into args. And ** packs keyword arguments as a dictionary into kwargs.

  • note: *args needs to be in front of **kwargs

In Function Call

If * and ** pack the arguments into tuple and dic in function definition, they unpack the list and dic into separate arguments.

def foo(a, b, c):
    print a, b, c

mylist = [1, 2]
mydic = {'c': 3}

foo(*mylist, **mydic)
# output
1 2 3

In above code, * unpacks mylist into 1, 2, ** unpacks mydic into c=3.
Then, foo receive the arguments as foo(1, 2, c=3).

Mix Arguments

The order the these arguments is:

  • regular argument, * argument, ** argument
def foo(a, b, c, *args, **kwargs):
    print a, b, c
    print args
    print kwargs

mylist = []
mydic = {'b': 2, 'd': 4}
foo(1, c=3, *mylist, **mydic)
# output
1 2 3
()
{'d': 4}

Anyway, alert the order both in definition or call, wrong order will cause error.