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)) # ?!
[]
The next() function returns the next item from the iterator. If the iterator is exhausted, it returns the default value passed as an argument.
The __iter__() function returns an iterator for the given object (array, set, tuple, etc. or custom objects). It creates an object that can be accessed one element at a time using __next__() function, which generally comes in handy when dealing with loops. Syntax : iter(object) iter(callable, sentinel)
Use enumerate() function to access the next item in a list in python for a loop. The for loop allows to access the variables next to the current value of the indexing variable in the list.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With