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