[Python-ideas] Rewriting the "roundrobin" recipe in the itertools documentation
Neil Girdhar
mistersheik at gmail.com
Thu Nov 16 15:16:29 EST 2017
I like yours better. Plenty of recipes sit on top of other recipes, e.g.,
pairwise sits on top of tee.
On Thursday, November 16, 2017 at 8:57:29 AM UTC-5, bunslow wrote:
>
> For taking values alternately from a series of iterables, there's two
> primary functions:
>
> builtin.zip
> itertools.zip_longest
>
> zip of course stops when the shortest iterable ends. zip_longest is
> generally a useful substitute for when you don't want the zip behavior, but
> it fills extra values in the blanks rather than just ignoring a finished
> iterator and moving on with the rest.
>
> This latter most use case is at least somewhat common, according to
> this[1] StackOverflow question (and other duplicates), in addition to the
> existence of the `roundrobin` recipe[2] in the itertools docs. The recipe
> satisfies this use case, and its code is repeated in the StackOverflow
> answer.
>
> However, it is remarkably unpythonic, in my opinion, which is one thing
> when such is necessary to achieve a goal, but for this functionality, such
> is most definitely *not* necessary. I'll paste the code here for quick
> reference:
>
>
> def roundrobin(*iterables):
> "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
> pending = len(iterables)
> nexts = cycle(iter(it).__next__ for it in iterables)
> while pending:
> try:
> for next in nexts:
> yield next()
> except StopIteration:
> pending -= 1
> nexts = cycle(islice(nexts, pending))
>
>
> Things that strike me as unpythonic: 1) requiring the total number of
> input iterables 2) making gratuitous use of `next`, 3) using a while loop
> in code dealing with iterables, 4) combining loops, exceptions, and
> composed itertools functions in non-obvious ways that make control flow
> difficult to determine
>
> Now, I get it, looking at the "roughly equivalent to" code for zip_longest
> in the docs, there doesn't seem to be much way around it for generally
> similar goals, and as I said above, unpythonic is fine when necessary
> (practicality beats purity), but in this case, for being a "recipe" in the
> itertools docs, it should *make use* of the zip_longest which already does
> all the unpythonic stuff for you (though honestly I'm not convinced either
> that the zip_longest code in the docs is the most possible pythonic-ness).
> Instead, the following recipe (which I also submitted to the StackOverflow
> question, and which is generally similar to several other later answers,
> all remarking that they believe it's more pythonic) is much cleaner and
> more suited to demonstrating the power of itertools to new developers than
> the mess of a "recipe" pasted above.
>
>
> def roundrobin(*iters):
> "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
> # Perhaps "flat_zip_nofill" is a better name, or something similar
> sentinel = object()
> for tup in it.zip_longest(*iters, fillvalue=sentinel):
> yield from (x for x in tup if x is not sentinel)
>
>
> In particular, this is just an extremely thin wrapper around zip_longest,
> whose primary purpose is to eliminate the otherwise-mandatory "fillvalues"
> that zip_longest requires to produce uniform-length tuples. It's also an
> excellent example of how to make best pythonic use of iterables in general,
> and itertools in particular, and as such a much better implementation to be
> demonstrated in documentation.
>
> I would thus advocate that the former recipe is replaced with the latter
> recipe, being much more pythonic, understandable, and useful for helping
> new developers acquire the style of python. (Using the common linguistics
> analogy: a dictionary and grammar for a spoken language may be enough to
> communicate, but we rely on a large body of literature -- fiction,
> research, poetry, etc -- as children to get that special flavor and most
> expressive taste to the language. The stdlib is no Shakespeare, but it and
> its docs still form an important part of the formative literature of the
> Python language.)
>
> I realize at the end of the day this is a pretty trivial and ultimately
> meaningless nit to pick, but I've never contributed before and have a
> variety of similar minor pain points in the docs/stdlib, and I'm trying to
> gauge 1) how well this sort of minor QoL improvement is wanted, and 2) even
> if it is wanted, am I going about it the right way. If the answers to both
> of these questions are positive regarding this particular case, then I'll
> look into making a BPO issue and pull request on GitHub, which IIUC is the
> standard path for contributions.
>
> Thank you for your consideration.
>
> ~~~~
>
> [1]:
> https://stackoverflow.com/questions/3678869/pythonic-way-to-combine-two-lists-in-an-alternating-fashion/
>
> [2]: https://docs.python.org/3/library/itertools.html#itertools-recipes
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20171116/40b6e498/attachment.html>
More information about the Python-ideas
mailing list