Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 84 additions & 44 deletions Doc/library/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
======================
Expand Down