In a parameter list (definition of a function) *args is Python's way of representing "variable arguments" (called "varargs" in C and C like languages). In an argument list (a call to a function) *args has the complementary meaning ... it "applies" the function to the value of the variable as if they'd been unpacked and "pasted" into the function's call.
This distinction between "parameters" and "arguments" is one that's often not elucidated. A parameter is a slot into which arguments are placed. Arguments are supplied to a function call. Parameters are the names by which arguments can be referred from within the scope of the function.
So if I define a function:
def foo(x, *a):
print "First arg: ", x
print "Other args: ", ' '.join([str(x) for x in a])
I can call it thus:
foo(1, 2, 3, 4)
... and my code will see 1 as "x" (the argument is an object reference to the integer 1, bound to the parameter named "x") and the list [2,3,4] as a (the argument will be an object reference to a three item list and bound to the function's parameter named "a").
If I bind the following tuple:
bar = (1, 2, 3, 4)
... and call foo()
thus:
foo(*bar)
... it will be a call that's identical to my previous example. "bar" will be unpacked, and passed to foo()
as a sequence of 4 arguments. This particular function would bind 1 to the first parameter and pack any number of other arguments into the a parameter. However I could call some other function:
geewhiz(*bar)
... and it would be passed four arguments just as I described for foo()
. (If geewhiz()
was written to take only 3 arguments then Python will raise a TypeError for calling a function with the wrong number of arguments ... exactly as it would if you called geewhiz(1,2,3,4)
.
In general Python's support for defining functions taking defaulted arguments, variable numbers of arguments, and keyword arguments is more flexible than any other scripting language I've ever seen. However all that power and flexibility can be a bit confusing.
In Python3 they've also added some wrinkles to tuple packing assignments. Tuple packing assignments look like:
a, b = 1, 2
... and also show up frequently in code like:
for key, val in my_dict.items():
...
Each of the items is being returned by the .items()
method as a tuple, and being packed into the key, val tuple. (Tuples in Python don't require enclosing parentheses. The , is the tuple-token).
Now in Python3 it's possible to do something like this:
a, *b = 1, 2, 3, 4
... which, as you might guess, binds the first element to "a" and the rest are packed into another tuple which is bound to "b."
While this really isn't related to *args in function parameter lists I mention it because they are conceptually and syntactically similar.