What do ** (double star/asterisk) and * (star/asterisk) mean in a function call?
F

5

796

In code like zip(*x) or f(**k), what do the * and ** respectively mean? How does Python implement that behaviour, and what are the performance implications?


See also: Expanding tuples into arguments. Please use that one to close questions where OP needs to use * on an argument and doesn't know it exists. Similarly, use Converting Python dict to kwargs? for the case of using **.

See What does ** (double star/asterisk) and * (star/asterisk) do for parameters? for the complementary question about parameters.

Friedrick answered 27/5, 2010 at 14:10 Comment(4)
addendum: #1142004Anadromous
I think this should be phrased as the "* function call syntax". They aren't operators, though it will get confusing as there is a * and ** operator that have nothing to do with this syntax.Hedve
@Ian Bicking: you are full right, * and ** in argument list are pure syntax (tokens).Mayhem
Note: For PEP 448: Additional Unpacking Generalizations specific stuff (e.g. [*a, b, *c] or {**d1, **d2}), you'll want to read asterisk in tuple, list and set definitions, double asterisk in dict definition, which is specific to the use outside of function calls and function definitions. For the earlier PEP 3132, see Multiple Unpacking Assignment in Python when you don't know the sequence length.Kesler
F
1193

A single star * unpacks a sequence or collection into positional arguments. Suppose we have

def add(a, b):
    return a + b

values = (1, 2)

Using the * unpacking operator, we can write s = add(*values), which will be equivalent to writing s = add(1, 2).

The double star ** does the same thing for a dictionary, providing values for named arguments:

values = { 'a': 1, 'b': 2 }
s = add(**values) # equivalent to add(a=1, b=2)

Both operators can be used for the same function call. For example, given:

def sum(a, b, c, d):
    return a + b + c + d

values1 = (1, 2)
values2 = { 'c': 10, 'd': 15 }

then s = add(*values1, **values2) is equivalent to s = sum(1, 2, c=10, d=15).

See also the relevant section of the tutorial in the Python documentation.


Similarly, * and ** can be used for parameters. Using * allows a function to accept any number of positional arguments, which will be collected into a single parameter:

def add(*values):
    s = 0
    for v in values:
        s = s + v
    return s

Now when the function is called like s = add(1, 2, 3, 4, 5), values will be the tuple (1, 2, 3, 4, 5) (which, of course, produces the result 15).

Similarly, a parameter marked with ** will receive a dict:

def get_a(**values):
    return values['a']

s = get_a(a=1, b=2)      # returns 1

this allows for specifying a large number of optional parameters without having to declare them.

Again, both can be combined:

def add(*values, **options):
    s = 0
    for i in values:
        s = s + i
    if "neg" in options:
        if options["neg"]:
            s = -s
    return s
        
s = add(1, 2, 3, 4, 5)            # returns 15
s = add(1, 2, 3, 4, 5, neg=True)  # returns -15
s = add(1, 2, 3, 4, 5, neg=False) # returns 15
Fellowman answered 27/5, 2010 at 14:15 Comment(7)
why would you need this, couldn't the function just iterate over the supplied list without it being expanded?Landes
Sure, but then you would have to call it: s = sum((1, 2, 3, 4, 5)) or s = sum([1, 2, 3, 4, 5]), the *values option makes the call look like it takes a number of arguments, but they're packed up into a collection for the function code.Fellowman
Here's the real benefit: you can write functions that wouldn't otherwise be possible if you need to have a variable number of arguments. For example, C's printf function, which has 1+n arguments, is tricky to write as an exercise for any beginning programmer. In Python, a beginner can write def printf(string_template, *args) and move on.Anticlerical
To give some motivation coming from a C background, the * acts in an analogous way as the * operator in C, in that it 'dereferences' the variable. In python context, this means essentially 'removing the outer braces' of arrays or dictionaries.Lindesnes
What happens if you (accidentally perhaps :p) unpack a dictionary with only one * instead of two? It seems to do something, it seems like a tuple comes out, but it is not so obvious what it is. (edit: ok I think the answer is that it just unpacks the keys, the values are discarded)Strow
The last example implies that * and ** are not only doing the unpacking but also packing! See this excellent page codingame.com/playgrounds/500/…Sphygmoid
@BenFarmer Yes; Python's dicts are iterable, and iterating over them yields the keys. So it is the same as if .keys() had been called on the dict first.Sitzmark
B
30

In a function call, the single star turns a list into separate arguments (e.g. zip(*x) is the same as zip(x1, x2, x3) given x=[x1,x2,x3]) and the double star turns a dictionary into separate keyword arguments (e.g. f(**k) is the same as f(x=my_x, y=my_y) given k = {'x':my_x, 'y':my_y}.

In a function definition, it's the other way around: the single star turns an arbitrary number of arguments into a list, and the double start turns an arbitrary number of keyword arguments into a dictionary. E.g. def foo(*x) means "foo takes an arbitrary number of arguments and they will be accessible through x (i.e. if the user calls foo(1,2,3), x will be (1, 2, 3))" and def bar(**k) means "bar takes an arbitrary number of keyword arguments and they will be accessible through k (i.e. if the user calls bar(x=42, y=23), k will be {'x': 42, 'y': 23})".

Barnes answered 27/5, 2010 at 14:13 Comment(0)
B
24

I find this particularly useful for storing arguments for a function call.

For example, suppose I have some unit tests for a function 'add':

def add(a, b):
    return a + b

tests = { (1,4):5, (0, 0):0, (-1, 3):3 }

for test, result in tests.items():
    print('test: adding', test, '==', result, '---', add(*test) == result)

There is no other way to call add, other than manually doing something like add(test[0], test[1]), which is ugly. Also, if there are a variable number of variables, the code could get pretty ugly with all the if-statements you would need.

Another place this is useful is for defining Factory objects (objects that create objects for you). Suppose you have some class Factory, that makes Car objects and returns them. You could make it so that myFactory.make_car('red', 'bmw', '335ix') creates Car('red', 'bmw', '335ix'), then returns it.

def make_car(*args):
    return Car(*args)

This is also useful when you want to call the constructor of a superclass.

Beltane answered 27/5, 2010 at 18:45 Comment(2)
I like your examples. But, I think -1 + 3 == 2.Knar
I intentionally put something in there that would fail :)Beltane
H
20

It is called the extended call syntax. From the documentation:

If the syntax *expression appears in the function call, expression must evaluate to a sequence. Elements from this sequence are treated as if they were additional positional arguments; if there are positional arguments x1,..., xN, and expression evaluates to a sequence y1, ..., yM, this is equivalent to a call with M+N positional arguments x1, ..., xN, y1, ..., yM.

and:

If the syntax **expression appears in the function call, expression must evaluate to a mapping, the contents of which are treated as additional keyword arguments. In the case of a keyword appearing in both expression and as an explicit keyword argument, a TypeError exception is raised.

Hamfurd answered 27/5, 2010 at 14:14 Comment(1)
Just adding a footnote to the textbook answer - before syntactical support arrived, the same functionality was achieved with the built-in apply() functionAstronomical
M
0

It is also useful when defining a dictionary that may have many keys with the same value. For Example,

d = {'a':'r1', 'b':'r1','c':'r1','d':'r2'}

can be written,

d = {**dict.fromkeys(['a','b','c'],'r1'),'d':'r2'}
Marcille answered 6/2 at 1:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.