728

What does the * operator mean in Python, such as in code like zip(*x) or f(**k)?

  1. How is it handled internally in the interpreter?
  2. Does it affect performance at all? Is it fast or slow?
  3. When is it useful and when is it not?
  4. Should it be used in a function declaration or in a call?
MisterMiyagi
  • 36,972
  • 7
  • 82
  • 99
psihodelia
  • 28,154
  • 35
  • 107
  • 154
  • addendum: http://stackoverflow.com/questions/1141504/name-this-python-ruby-language-construct-using-array-values-to-satisfy-function – wds May 27 '10 at 15:10
  • 4
    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. – Ian Bicking May 28 '10 at 02:45
  • 1
    @Ian Bicking: you are full right, * and ** in argument list are pure syntax (tokens). – P. Ortiz Oct 31 '15 at 21:13
  • 2
    Note: For [PEP 448: Additional Unpacking Generalizations](https://www.python.org/dev/peps/pep-0448/) 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](https://stackoverflow.com/q/36980992/364696), which is specific to the use *outside* of function calls and function definitions. For the earlier [PEP 3132](https://www.python.org/dev/peps/pep-3132/), see [Multiple Unpacking Assignment in Python when you don't know the sequence length](https://stackoverflow.com/q/2531776/364696). – ShadowRanger Mar 22 '19 at 20:14

5 Answers5

1099

The single star * unpacks the sequence/collection into positional arguments, so you can do this:

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

values = (1, 2)

s = sum(*values)

This will unpack the tuple so that it actually executes as:

s = sum(1, 2)

The double star ** does the same, only using a dictionary and thus named arguments:

values = { 'a': 1, 'b': 2 }
s = sum(**values)

You can also combine:

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

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

will execute as:

s = sum(1, 2, c=10, d=15)

Also see section 4.7.4 - Unpacking Argument Lists of the Python documentation.


Additionally you can define functions to take *x and **y arguments, this allows a function to accept any number of positional and/or named arguments that aren't specifically named in the declaration.

Example:

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

s = sum(1, 2, 3, 4, 5)

or with **:

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

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

this can allow you to specify a large number of optional parameters without having to declare them.

And again, you can combine:

def sum(*values, **options):
    s = 0
    for i in values:
        s = s + i
    if "neg" in options:
        if options["neg"]:
            s = -s
    return s

s = sum(1, 2, 3, 4, 5)            # returns 15
s = sum(1, 2, 3, 4, 5, neg=True)  # returns -15
s = sum(1, 2, 3, 4, 5, neg=False) # returns 15
Zero
  • 10,308
  • 7
  • 48
  • 68
Lasse V. Karlsen
  • 366,661
  • 96
  • 610
  • 798
  • 9
    why would you need this, couldn't the function just iterate over the supplied list without it being expanded? – Martin Beckett May 27 '10 at 14:27
  • 37
    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. – Lasse V. Karlsen May 27 '10 at 14:29
  • I don't think so. Replace `if neg:` with `if options['neg']:` or use `if options.get('neg', False)`, – glglgl Aug 07 '13 at 14:41
  • @glglgl Thanks, corrected. Wonder why I didn't see that problem. I must have skimped on testing :P – Lasse V. Karlsen Aug 07 '13 at 15:05
  • 14
    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. – IceArdor Nov 20 '13 at 07:38
  • What does this accomplish that simply passing a list or dictionary in as arguments doesn't? The only benefit I see is that you've expressed the type that should be passed in, but this seems like an incredibly stupid bandaid over the fact that Python lacks a means of including argument types in your function declaration. – ArtOfWarfare Dec 18 '13 at 16:50
  • 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. – user445786 Mar 08 '14 at 14:54
  • 2
    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) – Ben Farmer Sep 15 '17 at 07:47
  • 1
    The last example implies that * and ** are not only doing the unpacking but also packing! See this excellent page https://www.codingame.com/playgrounds/500/advanced-python-features#unpacking – H.C.Chen Feb 17 '19 at 04:06
  • @IceArdor That's what you use macros for in C –  Jul 15 '19 at 18:25
  • @mondlos Doesn't rely on the pre-processor to expand the macros? So it's not really pure C anymore, and the syntax isn't as clean or baked into the language as Python. I certainly wouldn't teach C to a beginning programmer on day 1, but I would teach Python `*args` to a beginning programmer on day 1 and `**kwds` on day 2. – IceArdor Dec 12 '19 at 06:14
  • `values = { 'a': 1, 'b': 2 } s = sum(**values)` does not work in python 3.8 – Soubriquet Aug 20 '20 at 02:43
  • @Soubriquet Why would it work? There are no arguments a or b on that method, so those will be placed into the additional options, which only look for the Neg option. – Lasse V. Karlsen Aug 20 '20 at 08:59
  • @LasseV.Karlsen This is the example you gave above. It would help to give a working example. – Soubriquet Aug 22 '20 at 03:49
  • in python 3.8.3 s = sum(1, 2, 3, 4, 5, neg=True) returns **15**, not **-15** – Lukkar Aug 25 '20 at 12:16
  • I am unable to reproduce that, it returns -15 here. I downloaded Python 3.8.3, put the sum function (bottom copy) + `print(sum(1, 2, 3, 4, 5, neg=True))` in a .py file, and executed it. It outputs -15. This also happens in the Python [shell](https://www.python.org/shell/). Can you post the exact code you tried? – Lasse V. Karlsen Aug 26 '20 at 12:58
52

One small point: these are not operators. Operators are used in expressions to create new values from existing values (1+2 becomes 3, for example. The * and ** here are part of the syntax of function declarations and calls.

Ned Batchelder
  • 345,440
  • 70
  • 544
  • 649
  • 8
    Note that the Python documentation does call * in this context an operator; I agree, that's kind of misleading. – Christophe Mar 18 '12 at 19:19
  • Thanks. I've been looking for a clear exposition of this in the python reference documentation and still don't see it. So the rule for function calls is basically that a "\*" or "**" that is at the beginning of an expression within a function call causes this sort of expansion? – nealmcb Nov 13 '12 at 14:36
22

In a function call the single star turns a list into seperate arguments (e.g. zip(*x) is the same as zip(x1,x2,x3) if x=[x1,x2,x3]) and the double star turns a dictionary into seperate keyword arguments (e.g. f(**k) is the same as f(x=my_x, y=my_y) if 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 the list 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 the dictionary k (i.e. if the user calls bar(x=42, y=23), k will be {'x': 42, 'y': 23})".

sepp2k
  • 353,842
  • 52
  • 662
  • 667
22

I find this particularly useful for when you want to 'store' 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 a superclass' constructor.

stuckoverflow
  • 584
  • 2
  • 7
  • 21
Donald Miner
  • 37,251
  • 7
  • 89
  • 116
19

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.

Mark Byers
  • 767,688
  • 176
  • 1,542
  • 1,434
  • 3
    Just adding a footnote to the textbook answer - before syntactical support arrived, the same functionality was achieved with the built-in `apply()` function – Jeremy Brown May 27 '10 at 14:20