What does "*list" mean?
zathras at thwackety.com
Fri Aug 1 00:13:05 CEST 2003
On 31 Jul 2003, Greg Smethells wrote:
> What exactly does "*values" mean in the following code?
One way of viewing it is that it flattens the list - expands the list as
separate arguments to be passed to the function. For those coming from a
perl background it makes the list act in the same way as a perl list
passed to a function not as a reference.
For sake of argument I'll use the following list, and 3 functions:
values=[1,2,3] # For sake of argument
def bar(args): # Simple case
def foo(*args): # Takes the arguments and turns it into tuple
def foobar(arg, *args): # Take first argument, and treat all others as
# part of a tuple called args
print arg, ":", args
Let's do the simple case first:
[1, 2, 3]
As you expect this succeeds - we passed one value to the function.
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: bar() takes exactly 1 argument (3 given)
The reason this failed is because
Is essentially equivalent to this:
Due to the "flattening" of the list.
The next case is where un-flattening happens (there's probably a better
phrase here :) :
([1, 2, 3],)
What's happened here? The call that was made is essentially this:
This hit the following signature:
This says to take the arguments, and stuff them into a tuple. We've only
passed one argument - specifically [1,2,3]. So a tuple is created using
this, which gives us our result : ([1,2,3], ) is displayed.
If we call foo with a normal argument list we get:
(1, 2, 3)
Why? Because *args in this context _effectively_ says "take the
(remaining) arguments, and create a single value named 'args' that is a
tuple containing those values". ie take the arguments 1,2,3, and create a
tuple - which is (1,2,3) which then gets displayed.
If we combine these things we quickly find some fun stuff. What happens if
we flatten a list that gets sent to a function that turns it's argument
list into a tuple?
(1, 2, 3)
We get this because foo(*values) is directly equivalent to foo(1,2,3) -
the list *values gets expanded/flattened.
Taking the final example function - what happens if you mix and match?
[1, 2, 3] : ()
Well, our signature here was:
>>> def foobar(arg, *args):
This says - take the first argument in the parameter list and stuff it in
"arg", if you get any other values, create a tuple with them, and stuff
them in args. In this case the first argument was the list [1,2,3], and
there were no further arguments, so args contains an empty tuple ()
If however we expand/flatten out list:
1 : (2, 3)
Our result is pretty clear: foobar(*values) has been treated as
foobar(1,2,3), the first argument -1- stuffed into arg, and the other two
stuffed into a tuple in args (1,2).
As a result this:
> >>> from struct import *
> >>> format = "dl"
> >>> values = [3.14, 42]
> >>> foo = pack(format, *values)
is directly equivalent to:
>>> from struct import *
>>> foo = pack("dl", 3.14, 42)
> More importantly still, how would you write the same code in C? If you
> wanted to instead call struct_pack(PyObject *tuple), what would the
> tuple look like in C?
Caveat: I haven't written any C extensions, not looked into the API and so
on, but I will point out this minor thing: how does this python function
differ from a normal one?
>>> def hello(world, everyone):
... print "hello", world, everyone
hello world today
Answer: it doesn't - it's just how the argument list has been built up. If
you were trying for the same effect in C, in principle, you'd either need:
* To do a varags call - ala printf (in which case the signature of what
you're calling would need to match) (This would match the "foobar"
* To upack the tuple into temporary values and then do the call
manually - as you could in python:
hello world today
There's probably a formal description of all this stuff somewhere :-)
More information about the Python-list