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