args v. *args passed to: os.path.join()

Heiko Wundram heikowu at ceosg.de
Sat Sep 18 14:08:35 EDT 2004


Before applying args or *args to a real world sample, lets see what each of 
them does:

>>> def testfunc(*args):
...   print args
...

Define a function called testfunc, for which all positional arguments are 
stored to the tuple args. The body of this functions contains a single 
statement which prints this tuple to screen.

>>> testfunc([1,2,3])
([1, 2, 3],)

The tuple which is printed to screen is the following: a tuple with a single 
item which is a list which contains the elements 1, 2 and 3 in this order.

>>> testfunc(*[1,2,3])
(1, 2, 3)

The tuple which is printed to screen is the following: a tuple with the items 
1, 2 and 3 in this order.

See where we're heading at? Let's see another example.

>>> def testfunc2(a,b):
...   print a
...   print b
...

Lets define another function which takes two arguments (a, b) and prints them 
out in order.

>>> testfunc2([1,2])
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: testfunc2() takes exactly 2 arguments (1 given)

Lets call this function with a single argument (a list, which contains the two 
items). The interpreter duly complains that the function takes two arguments, 
but only one is given, and raises a TypeError.

>>> testfunc2(*[1,2])
1
2

Again, using the star syntax: We pass two arguments (because the list which is 
starred contains two arguments), and these end up in a and b, respectively.

So, what does the star-operator do? It splits up an iterable (a list in this 
case) and fills the first len(iterable) positional arguments with the values 
it got from the list.

This is why you see different behavior when passing a star or not. Let's look 
at the documentation for os.path.join:

join(a, *p)
    Join two or more pathname components, inserting '/' as needed

This means that you have to pass at least one argument (a), which is the path 
base, and may pass more arguments (*p) which are joined with this item, 
inserting slashes as needed.

Now, when you call:

os.path.join(["a","b"])

the list ends up in the a parameter, and because the function doesn't have to 
do anything (there are no more arguments), the list is returned unchanged 
(although this should probably raise a TypeError, anyone?).

But when you call:

os.path.join(*["a","b"])

the first item of the list ends up as parameter a to the function, the second 
item of the list ends up as the second parameter to the function, which are 
then duly joined by the function.

And one more look why "".join(*["a","b"]) raises an error:

join(...)
    S.join(sequence) -> string

    Return a string which is the concatenation of the strings in the
    sequence.  The separator between elements is S.

The documentation for str.join() states that you pass it one parameter, a 
sequence.

Now, when you do "".join(*["a","b"]), the number of passed parameters is two, 
and because the function only accepts one parameter, a sequence, the function 
call raises an Exception.

HTH!

Heiko.



More information about the Python-list mailing list