Are multiple return values really harmful? (Re: determining the number of output arguments)

Bengt Richter bokr at oz.net
Fri Nov 19 09:10:32 EST 2004


On Fri, 19 Nov 2004 10:58:17 +0100, aleaxit at yahoo.com (Alex Martelli) wrote:

>Bengt Richter <bokr at oz.net> wrote:
>
>> >? No they're not -- a caller knows them, in order to be able to call
>> >with named argument syntax.
>> >
>> I guess you mean keyword arguments, so yes, 
>
>I hate to call them 'keyword' arguments when they aren't (check with the
>keyword module: it will confirm they aren't keywords!-).
>
Of the language no, but the error message is suggestive:

 >>> def foo(a,b,c): print a,b,c
 ...
 >>> foo(z=123)
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 TypeError: foo() got an unexpected keyword argument 'z'

OTOH, I have been arguing from an untested assumption *<8^P. I didn't
realize that 'keyword' style named parameter passing could be used
with the ordinary named parameters!

 >>> foo(b=2, a=1, c=3)
 1 2 3

That definitely is more than mnemonic. So the formal ordered parameter names
are not just internal information, they are part of the interface (which
you can optionally ignore). Really sorry if I misled anyone on that ;-/

>> but for other args I would argue that the caller's
>> knowledge of formal parameter names really only serves mnemonic purposes.
>
>How does that differ from returning a tuple-with-names?
I guess you are referring to those names' also being for optional use, i.e.,
that you can unpack a tuple-with-names the old fashioned way if you want. Hm...
but that might lead to ambiguities if we are to have automatic name-driven unpacking.
I.e.,

    c,a,b = tuple_with_names

might be different from

    c,a,b = tuple(tuple_with_names)

and

    a,b = tuple_with_names

might be a legal extraction of a and b (whatever the order), but

    a,b = tuple(tuple_with_names)[1:]

would need the [1:] to avoid an unpacking error.
That makes me wonder if

    a,b,c,etc = someobj

it will need an UNPACK_SEQUENCE that looks for a name-lookup
capability in someobj before it looks for an iter capability
to do sequential unpacking. I think probing __getitem__ would
cause problems, since dict is already capable of both __iter__
and __getitem__, and the priority is already defined:

 >>> a,b = {'x':1, 'y':2}
 >>> a,b
 ('y', 'x')


And since the underlying tuple would have to support __iter__,
I'm not sure how to generate code for name-driven unpacking
without having a __getnamedvalue__ method separate from __getitem__,
and which would have priority over __iter__. And then what do
you do with all those left-hand-side namelists that you mostly
won't need unless the RHS evaluates to an object with a __getnamedvalue__
method? Maybe we need to have an explict operator for name-driven unpacking, e.g.,

    a,b <- someobj

Then plain old __getitem__ could be used on any object that currently supports it,
and the name list would only be compiled into the code for explicit a,b <- something.

Obviously this could take care of unpacking tuple-with-name objects too.

>
>> I.e., once the calling code is written, e.g. an obfuscated-symbols
>> version of the function may be substituted with no change in program
>> behavior. So in that sense, there is no coupling: the writer of the
>
>If the caller doesn't use argument names, you can change argument names
>without breaking the caller.
That makes sense now, but I've been a caller who never used argument names
for the ordered parameters ;-)
>
>If the caller doesn't use field names in a returned tuple-with-names,
>you can change the field names without breaking the caller.
>
>I don't see any difference.
Nor do I now, except for the above aspect of ambiguity in automated
serial vs name-driven unpacking.

>
>> calling code is not forced to use any of the function's internal names
>
>Same for a tuple-with-names being returned.
Ok, yes, you can ignore the names. But if you do use names, you live with the
name choices of the function coder (both ways, as I've learned).
>
>> in _his_ source code. This is in contrast with e.g. a returned dict or
>> name-enhanced tuple: he _is_ forced to use the given actual names in _his_
>> code, much like keyword arguments again.
>
>Dicts are another issue.  As for tuples-with-names, no way:
But this is ignoring the names. See above re name-driven unpacking ;-)
>
>    a, b, c, d, e, f, g, h, i = time.localtime()
>
>this works, of course, and the caller doesn't have to know which field
>is named tm_day and which one tm_hour or whatever else, unless the
>caller WANTS to use such names for mnemonic purposes.
Ok, but name-driven unpacking will have to have other-than-plain-assignment
syntax, it now seems to me.

>
>The situation is as strictly parallel to passing functions to ordinary
>Python functions as two issues can ever be in programming: foo(a, b, c)
>works but so does foo(bar=b, baz=a, fee=c) if that's the calling style
>the caller prefers for mnemonic/clarity/style reasons.
>
Can you believe I've gone years without integrating the fact that any
named python parameter can be passed in name=value form? I've only used
them with ** syntax. Sheesh. Habits can be unnecessarily constraining ;-/

Regards,
Bengt Richter



More information about the Python-list mailing list