python – What does ** (double star/asterisk) and * (star/asterisk) do for parameters?

python – What does ** (double star/asterisk) and * (star/asterisk) do for parameters?

The *args and **kwargs is a common idiom to allow arbitrary number of arguments to functions as described in the section more on defining functions in the Python documentation.

The *args will give you all function parameters as a tuple:

def foo(*args):
    for a in args:
        print(a)        

foo(1)
# 1

foo(1,2,3)
# 1
# 2
# 3

The **kwargs will give you all
keyword arguments except for those corresponding to a formal parameter as a dictionary.

def bar(**kwargs):
    for a in kwargs:
        print(a, kwargs[a])  

bar(name=one, age=27)
# name one
# age 27

Both idioms can be mixed with normal arguments to allow a set of fixed and some variable arguments:

def foo(kind, *args, **kwargs):
   pass

It is also possible to use this the other way around:

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

obj = {b:10, c:lee}

foo(100,**obj)
# 100 10 lee

Another usage of the *l idiom is to unpack argument lists when calling a function.

def foo(bar, lee):
    print(bar, lee)

l = [1,2]

foo(*l)
# 1 2

In Python 3 it is possible to use *l on the left side of an assignment (Extended Iterable Unpacking), though it gives a list instead of a tuple in this context:

first, *rest = [1,2,3,4]
first, *l, last = [1,2,3,4]

Also Python 3 adds new semantic (refer PEP 3102):

def func(arg1, arg2, arg3, *, kwarg1, kwarg2):
    pass

Such function accepts only 3 positional arguments, and everything after * can only be passed as keyword arguments.

Note:

  • A Python dict, semantically used for keyword argument passing, are arbitrarily ordered. However, in Python 3.6, keyword arguments are guaranteed to remember insertion order.
  • The order of elements in **kwargs now corresponds to the order in which keyword arguments were passed to the function. – What’s New In Python 3.6
  • In fact, all dicts in CPython 3.6 will remember insertion order as an implementation detail, this becomes standard in Python 3.7.

Its also worth noting that you can use * and ** when calling functions as well. This is a shortcut that allows you to pass multiple arguments to a function directly using either a list/tuple or a dictionary. For example, if you have the following function:

def foo(x,y,z):
    print(x= + str(x))
    print(y= + str(y))
    print(z= + str(z))

You can do things like:

>>> mylist = [1,2,3]
>>> foo(*mylist)
x=1
y=2
z=3

>>> mydict = {x:1,y:2,z:3}
>>> foo(**mydict)
x=1
y=2
z=3

>>> mytuple = (1, 2, 3)
>>> foo(*mytuple)
x=1
y=2
z=3

Note: The keys in mydict have to be named exactly like the parameters of function foo. Otherwise it will throw a TypeError:

>>> mydict = {x:1,y:2,z:3,badnews:9}
>>> foo(**mydict)
Traceback (most recent call last):
  File <stdin>, line 1, in <module>
TypeError: foo() got an unexpected keyword argument badnews

python – What does ** (double star/asterisk) and * (star/asterisk) do for parameters?

The single * means that there can be any number of extra positional arguments. foo() can be invoked like foo(1,2,3,4,5). In the body of foo() param2 is a sequence containing 2-5.

The double ** means there can be any number of extra named parameters. bar() can be invoked like bar(1, a=2, b=3). In the body of bar() param2 is a dictionary containing {a:2, b:3 }

With the following code:

def foo(param1, *param2):
    print(param1)
    print(param2)

def bar(param1, **param2):
    print(param1)
    print(param2)

foo(1,2,3,4,5)
bar(1,a=2,b=3)

the output is

1
(2, 3, 4, 5)
1
{a: 2, b: 3}

Leave a Reply

Your email address will not be published.