summaryrefslogtreecommitdiffstats
path: root/Doc
diff options
context:
space:
mode:
authorRam Rachum <ram@rachum.com>2020-06-19 20:39:22 (GMT)
committerGitHub <noreply@github.com>2020-06-19 20:39:22 (GMT)
commit59cf853332a82ce92875ea3dd6bba08e1305a288 (patch)
treec7b2012089c6067d7c02ac5b57193605d3e498b0 /Doc
parent3358da4054b9b0b045eb47dc74dee3d58bfbb1d5 (diff)
downloadcpython-59cf853332a82ce92875ea3dd6bba08e1305a288.zip
cpython-59cf853332a82ce92875ea3dd6bba08e1305a288.tar.gz
cpython-59cf853332a82ce92875ea3dd6bba08e1305a288.tar.bz2
bpo-40636: Documentation for zip-strict (#20961)
Diffstat (limited to 'Doc')
-rw-r--r--Doc/library/functions.rst128
-rw-r--r--Doc/whatsnew/3.10.rst3
2 files changed, 87 insertions, 44 deletions
diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index e9c92f7..0577de6 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -1720,50 +1720,90 @@ are always available. They are listed here in alphabetical order.
dictionary are ignored.
-.. function:: zip(*iterables)
-
- Make an iterator that aggregates elements from each of the iterables.
-
- Returns an iterator of tuples, where the *i*-th tuple contains
- the *i*-th element from each of the argument sequences or iterables. The
- iterator stops when the shortest input iterable is exhausted. With a single
- iterable argument, it returns an iterator of 1-tuples. With no arguments,
- it returns an empty iterator. Equivalent to::
-
- def zip(*iterables):
- # zip('ABCD', 'xy') --> Ax By
- sentinel = object()
- iterators = [iter(it) for it in iterables]
- while iterators:
- result = []
- for it in iterators:
- elem = next(it, sentinel)
- if elem is sentinel:
- return
- result.append(elem)
- yield tuple(result)
-
- The left-to-right evaluation order of the iterables is guaranteed. This
- makes possible an idiom for clustering a data series into n-length groups
- using ``zip(*[iter(s)]*n)``. This repeats the *same* iterator ``n`` times
- so that each output tuple has the result of ``n`` calls to the iterator.
- This has the effect of dividing the input into n-length chunks.
-
- :func:`zip` should only be used with unequal length inputs when you don't
- care about trailing, unmatched values from the longer iterables. If those
- values are important, use :func:`itertools.zip_longest` instead.
-
- :func:`zip` in conjunction with the ``*`` operator can be used to unzip a
- list::
-
- >>> x = [1, 2, 3]
- >>> y = [4, 5, 6]
- >>> zipped = zip(x, y)
- >>> list(zipped)
- [(1, 4), (2, 5), (3, 6)]
- >>> x2, y2 = zip(*zip(x, y))
- >>> x == list(x2) and y == list(y2)
- True
+.. function:: zip(*iterables, strict=False)
+
+ Iterate over several iterables in parallel, producing tuples with an item
+ from each one.
+
+ Example::
+
+ >>> for item in zip([1, 2, 3], ['sugar', 'spice', 'everything nice']):
+ ... print(item)
+ ...
+ (1, 'sugar')
+ (2, 'spice')
+ (3, 'everything nice')
+
+ More formally: :func:`zip` returns an iterator of tuples, where the *i*-th
+ tuple contains the *i*-th element from each of the argument iterables.
+
+ Another way to think of :func:`zip` is that it turns rows into columns, and
+ columns into rows. This is similar to `transposing a matrix
+ <https://en.wikipedia.org/wiki/Transpose>`_.
+
+ :func:`zip` is lazy: The elements won't be processed until the iterable is
+ iterated on, e.g. by a :keyword:`!for` loop or by wrapping in a
+ :class:`list`.
+
+ One thing to consider is that the iterables passed to :func:`zip` could have
+ different lengths; sometimes by design, and sometimes because of a bug in
+ the code that prepared these iterables. Python offers three different
+ approaches to dealing with this issue:
+
+ * By default, :func:`zip` stops when the shortest iterable is exhausted.
+ It will ignore the remaining items in the longer iterables, cutting off
+ the result to the length of the shortest iterable::
+
+ >>> list(zip(range(3), ['fee', 'fi', 'fo', 'fum']))
+ [(0, 'fee'), (1, 'fi'), (2, 'fo')]
+
+ * :func:`zip` is often used in cases where the iterables are assumed to be
+ of equal length. In such cases, it's recommended to use the ``strict=True``
+ option. Its output is the same as regular :func:`zip`::
+
+ >>> list(zip(('a', 'b', 'c'), (1, 2, 3), strict=True))
+ [('a', 1), ('b', 2), ('c', 3)]
+
+ Unlike the default behavior, it checks that the lengths of iterables are
+ identical, raising a :exc:`ValueError` if they aren't:
+
+ >>> list(zip(range(3), ['fee', 'fi', 'fo', 'fum'], strict=True))
+ Traceback (most recent call last):
+ ...
+ ValueError: zip() argument 2 is longer than argument 1
+
+ Without the ``strict=True`` argument, any bug that results in iterables of
+ different lengths will be silenced, possibly mainfesting as a hard-to-find
+ bug in another part of the program.
+
+ * Shorter iterables can be padded with a constant value to make all the
+ iterables have the same length. This is done by
+ :func:`itertools.zip_longest`.
+
+ Edge cases: With a single iterable argument, :func:`zip` returns an
+ iterator of 1-tuples. With no arguments, it returns an empty iterator.
+
+ Tips and tricks:
+
+ * The left-to-right evaluation order of the iterables is guaranteed. This
+ makes possible an idiom for clustering a data series into n-length groups
+ using ``zip(*[iter(s)]*n, strict=True)``. This repeats the *same* iterator
+ ``n`` times so that each output tuple has the result of ``n`` calls to the
+ iterator. This has the effect of dividing the input into n-length chunks.
+
+ * :func:`zip` in conjunction with the ``*`` operator can be used to unzip a
+ list::
+
+ >>> x = [1, 2, 3]
+ >>> y = [4, 5, 6]
+ >>> list(zip(x, y))
+ [(1, 4), (2, 5), (3, 6)]
+ >>> x2, y2 = zip(*zip(x, y))
+ >>> x == list(x2) and y == list(y2)
+ True
+
+ .. versionchanged:: 3.10
+ Added the ``strict`` argument.
.. function:: __import__(name, globals=None, locals=None, fromlist=(), level=0)
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index 9c1dca1..8995845 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -79,6 +79,9 @@ New Features
:class:`types.MappingProxyType` object wrapping the original
dictionary. (Contributed by Dennis Sweeney in :issue:`40890`.)
+* :pep:`618`: The :func:`zip` function now has an optional ``strict`` flag, used
+ to require that all the iterables have an equal length.
+
Other Language Changes
======================