1''
1''

Reputation: 27125

Why does list(next(iter(())) for _ in range(1)) == []?

Why does list(next(iter(())) for _ in range(1)) return an empty list rather than raising StopIteration?

>>> next(iter(()))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> [next(iter(())) for _ in range(1)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> list(next(iter(())) for _ in range(1))  # ?!
[]

The same thing happens with a custom function that explicitly raises StopIteration:

>>> def x():
...     raise StopIteration
... 
>>> x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in x
StopIteration
>>> [x() for _ in range(1)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in x
StopIteration
>>> list(x() for _ in range(1))  # ?!
[]

Upvotes: 18

Views: 694

Answers (2)

wheaties
wheaties

Reputation: 35990

The StopIteration exception is used to tell the underlying mechanism of the list function when to actually stop iterating on the iterable that has been passed to it. In your case, you're telling Python that the thing that has been passed into list() is a generator. So when the generator throws a StopIteration before generating any items, it outputs an empty list because nothing has been accumulated.

Upvotes: 7

Tadhg McDonald-Jensen
Tadhg McDonald-Jensen

Reputation: 21474

assuming all goes well, the generator comprehension x() for _ in range(1) should raise StopIteration when it is finished iterating over range(1) to indicate that there are no more items to pack into the list.

However because x() raises StopIteration it ends up exiting early meaning this behaviour is a bug in python that is being addressed with PEP 479

In python 3.6 or using from __future__ import generator_stop in python 3.5 when a StopIteration propagates out farther it is converted into a RuntimeError so that list doesn't register it as the end of the comprehension. When this is in effect the error looks like this:

Traceback (most recent call last):
  File "/Users/Tadhg/Documents/codes/test.py", line 6, in <genexpr>
    stuff = list(x() for _ in range(1))
  File "/Users/Tadhg/Documents/codes/test.py", line 4, in x
    raise StopIteration
StopIteration

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/Tadhg/Documents/codes/test.py", line 6, in <module>
    stuff = list(x() for _ in range(1))
RuntimeError: generator raised StopIteration

Upvotes: 9

Related Questions