Other empty objects in Python evaluate as False -- how can I get iterators/generators to do so as well?
3 Answers
Guido doesn't want generators and iterators to behave that way.
Objects are true by default. They can be false only if they define __len__ that returns zero or __nonzero__ that returns False (the latter is called __bool__ in Py3.x).
You can add one of those methods to a custom iterator, but it doesn't match Guido's intent. He rejected adding __len__ to iterators where the upcoming length is known. That is how we got __length_hint__ instead.
So, the only way to tell if an iterator is empty is to call next() on it and see if it raises StopIteration.
On ASPN, I believe there are some recipes using this technique for lookahead wrapper. If a value is fetched, it is saved-up the an upcoming next() call.

- 216,523
- 63
- 388
- 485
-
1I am not suggesting that all iterators/generators should behave that way, only that sometimes it is useful for them to do so. For those times, my answer provides a way for it to happen. – Ethan Furman Nov 02 '11 at 13:30
-
Guido suggested that no iterators/generators should ever behave that way. – Raymond Hettinger Nov 02 '11 at 14:48
-
And one of the nice things about Python is that it doesn't (usually) stand in your way if you need/want to do something differently from the 'approved' method. (Don't get me started on `sum()`ing `str`s! ;) – Ethan Furman Nov 02 '11 at 15:29
-
That's called "going against the grain" of the language. It means your iterators won't be usable in code that assumes ``bool(it)`` is always *True*. Guido was able to produce examples of such code including some that he had written. (Just because you can assign False,True=1,0 doesn't mean you should ;-) – Raymond Hettinger Nov 02 '11 at 15:52
-
Indeed! Can you post a link to such code? I'm curious why one would bother checking the truth value of something that is always `True`. – Ethan Furman Nov 02 '11 at 16:15
-
You may have to search the python dev archives. IIRC, Guido was testing a value that could be an iterator or something else (I don't remember what). It was important enough that I needed to rip out the \_\_len\_\_ methods I had added to reversed(), enumerate(), and various itertools that had the ability to know their own length. – Raymond Hettinger Nov 02 '11 at 16:38
-
I was unhappily caught off-guard by this, writing code similar to `bool(x for x in [1,2,3] if x==val)` evaluating to `True` when `val==4` :( – Danra Dec 11 '18 at 09:10
-
1@Danra Use `any()` instead of `bool()`. It'd be nicer to write it as `any(x == val for x in [1,2,3])`. – Niccolo M. Aug 07 '22 at 13:12
By default all objects in Python evaluate as True
. In order to support False
evaluations the object's class must have either a __len__
method (0
-> False
), or a __nonzero__
method (False
-> False
). Note: __nonzero__
==> __bool__
in Python 3.x.
Because the iterator protocol is intentionally kept simple, and because there are many types of iterators/generators that aren't able to know if there are more values to produce before attempting to produce them, True
/False
evaluation is not part of the iterator protocol.
If you really want this behavior, you have to provide it yourself. One way is to wrap the generator/iterator in a class that provides the missing functionality.
Note that this code only evaluates to False
after StopIteration
has been raised.
As a bonus, this code works for pythons 2.4+
try:
next
except NameError: # doesn't show up until python 2.6
def next(iter):
return iter.next()
Empty = object()
class Boolean_Iterator(object):
"""Adds the abilities
True/False tests: True means there /may/ be items still remaining to be used
"""
def __init__(self, iterator):
self._iter = iter(iterator)
self._alive = True
def __iter__(self):
return self
def __next__(self):
try:
result = next(self._iter)
except StopIteration:
self._alive = False
raise
return result
next = __next__ # python 2.x
def __bool__(self):
return self._alive
__nonzero__ = __bool__ # python 2.x
If you also want look-ahead (or peek) behavior, this code will do the trick (it evaluates to False
before StopIteration
is raised):
try:
next
except NameError: # doesn't show up until python 2.6
def next(iter):
return iter.next()
Empty = object()
class Iterator(object):
"""Adds the abilities
True/False tests: True means there are items still remaining to be used
peek(): get the next item without removing it from the sequence
"""
def __init__(self, iterator):
self._iter = iter(iterator)
self._peek = Empty
self.peek()
def __next__(self):
peek, self._peek = self._peek, Empty
self.peek()
if peek is not Empty:
return peek
raise StopIteration
next = __next__ # python 2.x
def __bool__(self):
return self._peek is not Empty
__nonzero__ = __bool__ # python 2.x
def peek(self):
if self._peek is not Empty:
return self._peek
self._peek = next(self._iter, Empty)
return self._peek
Keep in mind that peek behaviour is not appropriate when the timing of the underlying iterator/generator is relevant to its produced values.
Also keep in mind that third-party code, and possibly the stdlib, may rely on iterators/generators always evaluating to True
. If you want peek without bool, remove the __nonzero__
and __bool__
methods.

- 63,992
- 20
- 159
- 237
-
Interesting Q&A, could one make use of `inspect.getgeneratorstate()` for this? – Chris_Rands Mar 14 '18 at 11:27
an 'empty thing' is automatically not an iterator. containers can be empty or not, and you can get iterators over the containers, but those iterators are not falsey when exhausted.
A good example of why iterators don't become falsey is sys.stdin
. The problem with making sys.stdin
falsey when it reaches the end of input is that there's no way of actually knowing if you have reached the end of such a stream without trying to consume input from it. The main reason for wanting an iterator to be falsey would be to 'peek' to see if getting the next item would be valid; but for sys.stdin
, that's obviously not practical.
here's another example
(x for x in xrange(1000) if random.randrange(0, 2))
there's no way of knowing if this generator will return any more numbers without doing a bunch of work, you actually have to find out what the next value will be.
The solution is to just get the next value from the iterator. If it is empty, your loop will exit, or you'll get a StopIteration
exception if you're not in a loop.

- 151,563
- 33
- 264
- 304
-
An empty iterator is still an iterator, and while peeking is the *main* reason, it's not the *only* reason. Also, it's clunky to use `StopIteration` in a boolean test. – Ethan Furman Nov 02 '11 at 13:56
-
1An iterator cannot be empty; only containers can be empty. Iterators are a 'place', like 'at the beginning', or 'column 5 of line 23'. – SingleNegationElimination Nov 02 '11 at 14:31
-
I'll have to think about that. Even along those lines, though, my code can be thought of as `True` if not 'past the end', `False` otherwise. – Ethan Furman Nov 02 '11 at 15:23
-
When you read from `sys.stdin` when `ctrl-D` has been pressed, the iterator will raise `StopException` as though it is empty, but the stream doesn't close, in fact, it effectively 'reopens', allowing further reading. There's no consistent concept of emptiness across all iterator types. The only feature is that is consistently available is `next()`, which may raise `StopIteraton` or not. – SingleNegationElimination Nov 02 '11 at 15:53
-
You said 'StopException' -- did you mean `StopIteration`? Once `StopIteration` has been raised, it should keep being raised on further `next()` calls or the iterator [is broken](http://docs.python.org/library/stdtypes.html?highlight=broken#iterator-types) – Ethan Furman Nov 02 '11 at 16:09
-
Yes, I know there's no consistent concept of emptiness acrocss all iterator types -- that's why my answer said "Note that the functionality is missing because there is no way to have it work reliably on every possible iterator/generator." – Ethan Furman Nov 02 '11 at 16:11
-
No, a further call to `next()` might not neccesarily raise another `StopIteration`, in fact `sys.stdin` does exactly this, it raises once for each terminal flush, but never really reaches 'the end' (unless closed by the application) – SingleNegationElimination Nov 02 '11 at 16:16
-
Yes, it might not -- that still means it's broken according to the docs. I also wouldn't recommend wrapping that type of iterator in my class. – Ethan Furman Nov 02 '11 at 16:38