Reputation: 13
I am trying to understand why using the sorted function on a zip
object in python 3 can't be done more than once. It just returns an empty list the second time.
In [34]: X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
...: Y = [ 0, 1, 1, 0, 1, 2, 2, 0, 1]
...: yx = zip(Y, X)
...: yx
...: [(0, 'a'), (1, 'b'), (1, 'c'), (0, 'd'), (1, 'e'), (2, 'f'), (2, 'g'),
...: (0, 'h'), (1, 'i')]
...: yx_sorted=sorted(yx)
...:
In [35]: yx_sorted
Out[35]:
[(0, 'a'),
(0, 'd'),
(0, 'h'),
(1, 'b'),
(1, 'c'),
(1, 'e'),
(1, 'i'),
(2, 'f'),
(2, 'g')]
In [36]: yx_sorted=sorted(yx)
In [37]: yx_sorted
Out[37]: []
In [38]: yx
Out[38]: <zip at 0x10476aa88>
yx
is still there as far as I can see.
Upvotes: 1
Views: 95
Reputation: 19144
In CPython 3, zip is a class, which means it is a callable, which means it is a function in the wide, mathematical sense of the term. It is documented in the Built-in Functions
chapter of the Library Manual
.
When called, CPython's zip
returns a zip object
, which is an iterator as the document entry says ("returns an iterator"). It has an __iter__
method that returns self
and a __next__
method with the appropriate behavior. Since a zip object is an iterator, it is exhausted after the first complete iteration performed by sorted
.
In the doc entry, the roughly equivalent Python code is for a generator function, which when called returns a generator. (Since CPython built-in functions are coded in C, and generator functions can only be coded in Python, CPython implements it as a class.) This is why people somewhat mistakenly say that zip returns a generator. However, since the generator produced by the equivalent code is only usable as an iterator, the effect would be the same, and "returns an iterator" would still be true. If any implementation (other than CPython) uses the Python code (PyPy?), then for that implementation, zip
would be a generator.
EDIT: Add link to doc entry, and the following:
Since X and Y in the question are reiterable, zip(X, Y)
can be repeated to get a new, fresh iterable with the same sequence of pairs. sorted(zip(X,Y))
will work multiple times.
Upvotes: 1
Reputation: 402
I'm unable to replicate this in the shell using 2.7.13
>>> X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
>>> Y = [ 0, 1, 1, 0, 1, 2, 2, 0, 1]
>>> yx = zip(X, Y)
>>> yx
[('a', 0), ('b', 1), ('c', 1), ('d', 0), ('e', 1), ('f', 2), ('g', 2), ('h', 0), ('i', 1)]
>>> yx_sorted = sorted(yx)
>>> yx_sorted
[('a', 0), ('b', 1), ('c', 1), ('d', 0), ('e', 1), ('f', 2), ('g', 2), ('h', 0), ('i', 1)]
>>> yx
[('a', 0), ('b', 1), ('c', 1), ('d', 0), ('e', 1), ('f', 2), ('g', 2), ('h', 0), ('i', 1)]
>>> yx_sorted = sorted(yx)
>>> yx_sorted
[('a', 0), ('b', 1), ('c', 1), ('d', 0), ('e', 1), ('f', 2), ('g', 2), ('h', 0), ('i', 1)]
>>> yx
[('a', 0), ('b', 1), ('c', 1), ('d', 0), ('e', 1), ('f', 2), ('g', 2), ('h', 0), ('i', 1)]
>>>
Are you using a Jupyter notebook? Perhaps it's something to do with that, and not Python itself?
Upvotes: 0
Reputation: 599560
zip
is a generator in Python 3. Once you've iterated it once, it's exhausted.
Upvotes: 5