determining the number of output arguments

Alex Martelli aleaxit at yahoo.com
Tue Nov 16 02:14:16 EST 2004


Josiah Carlson <jcarlson at uci.edu> wrote:

> > a, b, c, d = lotsa[:4]
> > 
> > _should_ properly give the impression of a code smell, if your "once and
> > only once" sense is finely tuned.  What's the business of that ':4' on
> > the RHS?  Showing the compiler that you can count correctly?!  You're
   ...
> The slicing on the right is not so much to show the compiler that you
> know how to count, it is to show the runtime that you are looking for
> a specified slice of lotsa.  How would you like the following two cases
> to be handled by your desired Python, and how would that make more sense
> than what is done now?
> 
> a,b,c = [1,2,3,4]
> a,b,c = [1,2]

I would like to get exceptions in these cases, which, being exactly what
IS done now, makes exactly as much sense as itself.  Note that there is
no indicator in either of these forms that non-rigid unpacking is
desired.  Assuming the indicator for 'and all the rest' were a prefix
star, then:

a, b, *c = [1, 2, 3, 4]
a, b, *c = [1, 2]

should both set a to 1, b to 2, and c respectively to [3, 4] and [].  Of
course there would still be failing cases:

a, b, *c = [1]

this should still raise -- 'a, b, *c' needs at least 2 items to unpack.


> > I think it would be better to have a way to say 'and all the rest'.
> > Lacking that, some automated way to count how many items are being
> > unpacked on the LHS is probably second-best.
> 
> Is it worth a keyword, or would a sys.getframe()/bytecode hack be
> sufficient? In the latter case, I'm sure you could come up with such a
> mechanism, and when done, maybe you want to offer it up as a recipe in
> the cookbook *wink*.

Two recipes in the 2nd ed of the CB can be combined to that effect
(well, nearly; c becomes an _iterator_ over 'all the rest'), one by
Brett Cannon and one by Sami Hangaslammi.  Not nearly as neat and clean
as if the language did it, of course.


> > Another case where a specific number of items is requested, which is not
> > (syntactically speaking) a multiple assignment, is assignment to an
> > _extended_ slice of, e.g., a list (only; assignment to a slice with a
> > stride of 1 is happy with getting whatever number of items are coming).
> > I don't particularly LIKE writing:
> >     L[x:y:z] = len(L[x:y:z]) * [foo]
> 
> I much prefer...
> 
> for i in xrange(x, y, z):
>     L[i] = foo

Not the same semantics, in the general case.  For example:

   L[1:-1:2] = ...

rebinds (len(L)/2)-1 items; your version rebinds no items, since
xrange(1, -1, 2) is empty.  To simulate the effect that assigning to an
extended slice has, you have to take a very different tack:

for i in slice(x, y, z).indices(len(L)):
    L[i] = foo

and that's still quite a bit less terse and elegant, as is usually the
case for fussy index-based looping whenever it's decently avoidable.

> But then again, I don't much like extended list slicing (I generally
> only use the L[:y], L[x:] and L[x:y]  versions).

It may be that in your specific line of work there is no opportunity or
usefulness for the stride argument.  Statistically, however, it's
somewhat more likely that you're not taking advantage of the
opportunities because, given your dislike, you don't even notice them --
as opposed to the opportunities not existing at all, or you noticing
them, evaluating them against the lower-level index-based-looping
alternatives, and selecting the latter.  If you think that extended
slices are sort of equivalent to xrange, as above shown, for example,
it's not surprising that you're missing their actual use cases.


Alex





More information about the Python-list mailing list