简体   繁体   中英

Doubley unpacking an iterable in Python 3 removes the iterable?

lst = iter([1, 2, 3])
print([*lst])  # >>> [1, 2, 3]
print([*lst])  # >>> []

Is this expected behaviour for unpacking? I would've assumed the original data wouldn't be modified on unpacking and a copy is simply made?

EDIT:

If so, what is the reasoning behind it?

Yes, this is expected behavior for unpacking an iterator :

>>> lst = [1, 2, 3]
>>> iter(lst)
<list_iterator at 0x7fffe8b84ef0>

The iterator can only be iterated once and then it is exhausted.

>>> i = iter(lst)
>>> next(i)
1
>>> next(i)
2
>>> next(i)
3
>>> next(i)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-11-a883b34d6d8a> in <module>()
----> 1 next(i)

StopIteration: 

The iterator protocol specifies that an exhausted iterator must continue raising StopIteration exceptions on subsequent calls of its __next__ method. Therefore, iterating it once again is valid (not an error), but the iterator should yield no new items:

>>> list(i)
[]

Nothing prevents you to define an iterator which disobeys this rule, but such iterators are deemed "broken" .

The list iterable could be unpacked multiple times, however.

>>> lst = [1, 2, 3]
>>> print(*lst)
1 2 3
>>> print(*lst)
1 2 3

And you could create as many independent iterators, from the same source list, as you want:

>>> i1 = iter(lst)
>>> i2 = iter(lst)
>>> next(i2)
1
>>> next(i2)
2
>>> next(i1)  # note: it's another 1
1

From the glossary entry for iterators (my emphasis):

A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container.

You are confusing the terminology of "iterator" and "iterable".

An iterator (typically) can't be iterated over again. An iterable on the other hand (like a list) can:

lst = [1, 2, 3]
print([*lst])  # >>> [1, 2, 3]
print([*lst])  # >>> [1, 2, 3]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM