def a((b,c,d),e):

George Sakkis gsakkis at rutgers.edu
Tue Apr 19 13:41:31 EDT 2005


"François Pinard" wrote:
>
> I started recently to study the R system and language, and saw many
good
> ideas in there about argument passing.  Translated in Python terms,
it
> would mean that `*varargs' and `**keywords' are not necessary last,
> that named keywords may be intermixed with positional keywords, that

This would be neat indeed. Occasionally I come across situations where
I wished to be able to specify default arguments after positional, as
for example in "def accumulate(*items, default=0)". The current
possible workarounds are:
- pass an iterable instead of positional arguments: "def
accumulate(items, default=0)". This is not always elegant, especially
if the function is called with few independently derived items (as
opposed, for example, to items derived by a list/generator
comprehension, which is already an iterable).
- pass named keywords instead of default: "def accumulate(*items,
**kwds)". I tend to think of **kwds as a nice feature for functions
with almost open-ended functionality, that intend to be extended in the
future with more customization options. In more typical cases though of
a function with one or two defaults, using **kwds obscures the
function's signature without a visible benefit. Also, I'm not sure of
the efficiency penalty imposed by constructing and passing a dict of
length 1 or 2 instead of default arguments.
- Put the default(s) before the positional arguments: "def
accumulate(default=0, *items)". This practically negates the purpose of
using defaults in the first place since the first passed argument is
bounded to default.

Allowing non-default arguments after *varargs doesn't make sense, but
it does for default arguments. The parameter binding rule would just
need to be augmented so that default parameter arguments after *varargs
would be bounded to their default value unless specified explicitly in
the call as named arguments:
accumulate(1,2) == accumulate(1,2 default=0) and
accumulate([1],[2],default=[]) == accumulate([1],default=[], [2])  ==
accumulate(default=[], [1], [2])

> keywords may be abbreviated, and much more hairy,

Hmm.. -1 on this. It may save a few keystrokes, but it's not good for
readability and maintenability.

> that the default
> values for keywords are not pre-evaluated at `def' time, and that


Definitely a +1 on this. I've always seen pre-evaluation as a wart,
especially with respect to mutable default values. If some sort of
state needs to be preserved between calls, the right way is to
encapsulate it in class, not in a default value.

> the computation of actual expressions given as arguments is lazily
> postponed until their first use within the function.

Is this like an implicit lambda before each argument ? If so, why does
it have to be restricted to function arguments ? It seems to me that
argument passing and lazy evaluation are orthogonal dimensions. Let's
keep the "should python become lazy ?" question for a future thread :-)

Concerning default argument expressions, a neat feature would be to
allow an expression to refer to other arguments, as in "def
foo(a,b,s=a+b)" instead of the current workaround which goes like:
def foo(a,b,s=None):
    if s is None: s = a+b
Or for a more exotic use:
def prologLikeSum(a=s-b, b=s-a, s=a+b):
    return a,b,s
prologLikeSum(1,2) == prologLikeSum(1,s=3) == prologLikeSum(b=2,s=3) ==
(1,2,3)

This seems pretty hard to change though. For one thing, it would
require new syntax to denote which names in the expression refer to
other arguments instead of the enclosing scope. Also the binding of
arguments to values would no more be considered "parallel"; the order
of the bindings would be significant, and even worse, it would have to
be computed for each call, as the prologLikeSum example shows.

Probably-I'm-just-rambling-ly yrs
George




More information about the Python-list mailing list