default tuple unpacking?

Huaiyu Zhu huaiyu at gauss.almadan.ibm.com
Wed Sep 4 14:16:07 EDT 2002


Peter Hansen <peter at engcorp.com> wrote:
>Peter Hansen wrote:
>> Huaiyu Zhu wrote:
>> 
>>> It is often very convenient to have default arguments such as
>>>
>>>     def func(a, b, *c): ...
>>>
>>> Is there a way to use this in statements too?  Examples:
>>>
>>>     a, (b, *c), *d = e
>
>Hmm... I think there might be an inconsistency or an unexpected
>result in this.  What if e already contains a tuple?

Bengt Richter and Bernhard Herzog have already given two different answers
to this question.  Both are consistent in themselves.  I feel that Bengt's
answer is more elegant, but it runs againt the Python syntax rule that
tuples are made from commas instead of parentheses.

Bernhard's answer can easily fit in the current syntax. I'll expand it in
more detail to make sure there is no ambiguity.  Consider

    def func0(*a):          return *a
    def func1(a, *b):       return a, *b
    def func2(a, b, *c):    return a, b, *c

For func in [func0, func1, func2], the following are equivelant

    x, y, *z = func(a, b, *c)
    x, y, *z = a, b, *c

For func in [func0, func1], the following are equivelant

    x, *y = func(a, *b)
    x, *y = a, *b

For func in [func0, func1], the following are equivelant

    x, = func(a)
    x, = a,

The following are always equivelant

    *x = func0(*a)
    *x = *a
    x = tuple(a)

Let's see if this works for all your examples:

>
>   e = (1, 2, 3)
>   *a = e        # a is ((1, 2, 3), )

This is equivalent to

    a = e  # a = 1,2,3

This equivalence may look disturbing, but I can't think of any trouble it
might cause.  Following are more equivelences of this sort

    a = *e
    *a = *e
    a = 1, 2, 3
    *a = 1, 2, 3
    a = *(1, 2, 3)
    *a = *(1, 2, 3) 

>
>That seems sensible, and it's just what happens if you pass
>"e" in to a function defined as "def func(*a)".

This is equiv to

    *a = e,   # a = (1,2,3),

>
>Now what about this:
>
>   a, *b = e     # a is 1, b is (2, 3)
>

Yes.

>That's one possible result, and presumably the one you want with
>this syntax, but it's not what you'd get with the function syntax:
>
>   def func(a, *b):
>     print a
>     print b
>
>   func(e)

That's

    a, *b = e,   # a = 1, 2, 3; b=()

>
>Here of course you get (1, 2, 3) in "a" and () in b.  To get the
>same as the proposed syntax above, you can't pass in a tuple, but
>have to pass the parameters separately:
>
>   func(1, 2, 3)  # now a is 1, b is (2, 3)

That's

    a, *b = 1, 2, 3  # a = 1; b = 2,3

>
>The problem is that in function calling, you can pass in a single
>tuple, which is one argument, or you can pass the elements separately
>as multiple arguments, which is when the special * syntax kicks in.

Always think of function arguments as a tuple. If the argument is a single
tuple, then the args is simply a single-element tuple whole element happens
to be a tuple.

Huaiyu



More information about the Python-list mailing list