Re: passing/catching a variable number of args in python

Guido van Rossum (guido@cwi.nl)
Thu, 12 Dec 91 14:08:32 +0100

You did a fine job: you've convinced me that there is a way to change
Python's argument passing without breaking the whole language, and
allowing several problems with arguments to be fixed. I even think
that this can be done in an almost backward-compatible way (which is
important to myself, since I've got over 10,000 lines of Python code
lying around...).

Still no guarantees that I'll do it, but it sounds attractive since it
would solve two current problems: the exceptional position of
functions without arguments and the weird argument lists required for
methods.

I don't think it is necessary to change assignments at all. The most
important new rule would be:

1. Formal and actual parameter lists are *always* seen as
tuples: a single parameter is seen as a singleton tuple, an
empty parameter list is seen as an empty tuple.

(It is important to realize that in Python the caller has no idea of
the callee's formal parameter list, so there must be an agreed upon
representation of actual parameter lists.)

Two extra rules provide coercion between tuples and single parameters;
these are only invoked (in the callee, when receiving the argument
list) if the number of actual and formal parameters don't match:

2. If there is exactly one actual parameter and 0 or 2 or more
formal parameters, the actual parameter must be a tuple with
as many items, and its items are distributed over the formal
parameters.

3. If there is exactly one formal parameter and 0 or 2 or more
actual parameters, the formal paramater receives the tuple of
actual parameters.

Rule 2 makes it possible to do:

def f(a, b, c): ...

x = 1, 2, 3
f(x) # equivalent to f(1, 2, 3)

which is important if you have a function and an argument list that
you want to save somewhere (perhaps pass it to another module) so it
can be called later. The old system had an anomaly that such a module
couldn't both handle function calls with and without arguments; the
new system lets you pass "f, ()" in this case.

Rule 3 handles the reverse case:

def f(x): ...

f(1, 2, 3) # equivalent to f((1, 2, 3))

which makes it possible to let the function detect the number of
arguments. This still requires the callee to handle a single actual
parameter special (since then the formal parameter won't be a tuple).
Also this mechanism makes it impossible to pass a variadic function
one argument which is a tuple -- I'm not sure if this is a problem,
but if it is, we are now able to define special syntax in the formal
parameter list to handle variable length argument lists special (e.g.,
&rest).

One problem left to solve is the mapping from method calls to function
calls. We can now get rid of the silly convention that a method with
more than one argument must enclose all arguments except "self" in
extra parentheses:

# old style
class C():
def method(self, (x, y, z)): ...

can now become

# new style
class C:
def method(self, x, y, z): ...

I haven't thought about a backward compatibility hack here -- perhaps
I'll solve that with a script...

Now I have to get back to your mail.

>def f((x), y)
>
>f((1), 2) -- x gets 1
>f((1, 2), 3) -- this I don't like. should x get tuple (1, 2)? I say no.
> -- an error would be more consistent. what does python do?

Currently "def f((x), y)" is indistinguishable from "def f(x, y)",
just as "(1)+1" is indistinguishable from "1+1". I'd like to keep
this rule in general. My proposal above only makes the outermost
parentheses of function calls and declarations special.

>I propose that instead of a = 1, 2, 3, one must say a = (1, 2, 3)

I don't see why this requirement would improve the language.

>and instead of def f(a) given f(1, 2, 3) one must say f((1, 2, 3)).

Not with my proposal, because of rule 3.

>Had you considered matching corresponding elements of lists too?
>So def f([a, b]) could be given f([1, 2]).

Not too useful, since lists are mostly used when they may vary in
length.

--Guido van Rossum, CWI, Amsterdam <guido@cwi.nl>
"That was never five minutes just now!"
"I'm afraid it was."