Python Iterables struggling using map() built-in
Terry Reedy
tjreedy at udel.edu
Sun Dec 7 19:38:08 EST 2014
On 12/7/2014 7:12 PM, Roy Smith wrote:
> Chris Angelico wrote:
>>> I'm actually glad PEP 479 will break this kind of code. Gives a good
>>> excuse for rewriting it to be more readable.
>
> Steven D'Aprano <steve+comp.lang.python at pearwood.info> wrote:
>> What kind of code is that? Short, simple, Pythonic and elegant? :-)
>>
>> Here's the code again, with indentation fixed:
>>
>>
>> def myzip(*args):
>> iters = map(iter, args)
>> while iters:
>> res = [next(i) for i in iters]
>> yield tuple(res)
>
> Ugh. When I see "while foo", my brain says, "OK, you're about to see a
> loop which is controlled by the value of foo being changed inside the
> loop". That's not at all what's happening here, so my brain runs into a
> wall.
I agree. Too tricky. The code should have been
def myzip(*args):
if args:
iters = map(iter, args)
while True:
res = [next(i) for i in iters]
yield tuple(res)
However, this 'beautiful' code has a trap. If one gets rid of the
seemingly unneeded temporary list res by telescoping the last two lines
into a bit too much into
yield tuple(next(i) for i in iters)
we now have an infinite generator, because tuple() swallows the
StopIteration raised as a side-effect of next calls.
def myzip(*args):
if args:
iters = map(iter, args)
while True:
try:
result = [next(i) for i in iters]
except StopIteration
return
yield tuple(res)
makes the side-effect dependence of stopping clearer. Putting
yield tuple([next(i) for i in iters])
in the try would also work.
--
Terry Jan Reedy
More information about the Python-list
mailing list