From 540439a62976c0f5fcdfc7bfad214e33f8df691e Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Thu, 24 Aug 2017 18:04:01 +0200 Subject: [PATCH 1/2] bpo-31270: Simplify documentation of itertools.zip_longest --- Doc/library/itertools.rst | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index b0d0a8c8c8ccd7..01cdd3f1f5cd32 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -630,26 +630,26 @@ loops that truncate the stream. iterables are of uneven length, missing values are filled-in with *fillvalue*. Iteration continues until the longest iterable is exhausted. Roughly equivalent to:: - class ZipExhausted(Exception): - pass - - def zip_longest(*args, **kwds): - # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- - fillvalue = kwds.get('fillvalue') - counter = len(args) - 1 - def sentinel(): - nonlocal counter - if not counter: - raise ZipExhausted - counter -= 1 - yield fillvalue - fillers = repeat(fillvalue) - iterators = [chain(it, sentinel(), fillers) for it in args] - try: - while iterators: - yield tuple(map(next, iterators)) - except ZipExhausted: - pass + def zip_longest(*args, **kwds): + # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- + fillvalue = kwds.get('fillvalue') + iterators = [iter(it) for it in args] + + while True: + exhausted = 0 + values = [] + + for it in iterators: + try: + values.append(next(it)) + except StopIteration: + values.append(fillvalue) + exhausted += 1 + + if exhausted < len(args): + yield tuple(values) + else: + break If one of the iterables is potentially infinite, then the :func:`zip_longest` function should be wrapped with something that limits the number of calls From 7e7ff5b15d3d60a4c62deed531d1ca1d97476529 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 7 Sep 2017 12:35:17 -0700 Subject: [PATCH 2/2] Use repeat(). Track num_active. --- Doc/library/itertools.rst | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 01cdd3f1f5cd32..c989e464200d8b 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -630,26 +630,25 @@ loops that truncate the stream. iterables are of uneven length, missing values are filled-in with *fillvalue*. Iteration continues until the longest iterable is exhausted. Roughly equivalent to:: - def zip_longest(*args, **kwds): - # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- - fillvalue = kwds.get('fillvalue') - iterators = [iter(it) for it in args] - - while True: - exhausted = 0 - values = [] - - for it in iterators: - try: - values.append(next(it)) - except StopIteration: - values.append(fillvalue) - exhausted += 1 - - if exhausted < len(args): - yield tuple(values) - else: - break + def zip_longest(*args, fillvalue=None): + # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- + iterators = [iter(it) for it in args] + num_active = len(iterators) + if not num_active: + return + while True: + values = [] + for i, it in enumerate(iterators): + try: + value = next(it) + except StopIteration: + num_active -= 1 + if not num_active: + return + iterators[i] = repeat(fillvalue) + value = fillvalue + values.append(value) + yield tuple(values) If one of the iterables is potentially infinite, then the :func:`zip_longest` function should be wrapped with something that limits the number of calls