determining the number of output arguments

Josiah Carlson jcarlson at uci.edu
Tue Nov 16 13:45:02 EST 2004


aleaxit at yahoo.com (Alex Martelli) wrote:
> 
> 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.

The only limitation right now is Guido.  That is, you need to convince
Guido, and likely get the syntax implemented.  See James Knight's post
on 11/12/2004 in python-dev (or my recent quoting here) with a quote
from Guido in regards to this syntax.


> > > 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.

I have another response to this...what would be shorter, using some
automated 'how many items are on the left' discovery mechanism, or just
putting in the ':4'?

Certainly some symbol could be reused for something like...
a,b,c = L[:%]  #first part
a,b,c = L[%:]  #last part, automatically negating the value

But is something like the follwing even desireable?
a,b,c = L[i:%:j] #automatically calculate the ending index
a,b,c = L[%:i:j] #automatically calculate the start index

Regardless, I'm not sure I particularly like any symbol that could be
placed in either set of slices.  If it is not some single-character
symbol, then it is actually shorter to just count them.


> > 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.

What is to stop the recipes from wrapping that final iterator with a
list() call?


> > > 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] = ...

And I would just use...

for i in xrange(1, len(L)-1, 2):
    L[i] = ...

As in anything, if there is more than one way to do something, at least
a bit of translation is required.


> 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.

You know, terse != elegant.  While extended slice assignments are terse,
I would not consider them elegant.  Elegant is quicksort, the
Floyd-Warshall algorithm for APSP, Baruvka's MST algorithm, etc.  Being
able to say "from here to here with this stride", that's a language
convenience, and its use is on par with using fcn(*args, **kwargs).


Have I used it?  Sure, a few times.  My most memorable experience is
using a similar functionality in C with MPI.  Unbelievably useful for
chopping up data for distribution and reintegration.  Was it elegant, I
wouldn't ever make such a claim, it was a library feature, and extended
slice assignments in Python are a language feature.  A useful language
feature for a reasonably sized subset of the Python community certainly,
but elegant, not so much.


Using an imperative programming style with Python (using indices to
index a sequence), I thought, was to be encouraged; why else would
xrange and range be offered?  Oh, I know, because people use 'fussy
index-based looping' in C/C++, Java, pascal...and don't want to change
the way they develop.  Or maybe because not every RHS is a sequence, and
sequence indexing is the more general case which works for basically
everything (with minimal translation).


> > 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.

It is the case that I have rarely needed to replace non-contiguous
sections of lists.  It has been a few years since I used MPI and the
associated libraries.  Recently in those cases that I have found such a
need, I find using xrange to be far more readable. It's an opinion thing,
and we seem to differ in the case of slice assignments (and certainly a
few other things I am aware of). How about we agree to disagree?

I have also found little use of them in the portions of the standard
library that I peruse on occasion, which in my opinion, defines what it
means to be Pythonic (though obviously many extended slice usages are
application-specific).


 - Josiah




More information about the Python-list mailing list