Python
iterators
hasnext
Python programming
iterator methods

hasnext for Python iterators?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Python iterators do not have a built-in hasNext() method like Java iterators. Instead, the iterator protocol is based on calling next() until StopIteration is raised. That design is intentional: most Python code is written with for loops and iterator-consuming functions rather than explicit "is there another item" checks.

The Python Iterator Protocol

An iterator in Python implements two ideas:

  • 'iter(obj) returns an iterator'
  • 'next(iterator) returns the next item or raises StopIteration'
python
1values = [10, 20, 30]
2it = iter(values)
3
4print(next(it))
5print(next(it))
6print(next(it))

If you call next(it) one more time, Python raises StopIteration. That exception is not an error in the normal sense. It is the protocol signal that iteration has finished.

Why Python Usually Does Not Need hasNext

In most cases, you should not ask whether an iterator has another item. You should just iterate.

python
values = [10, 20, 30]
for value in values:
    print(value)

The for loop already handles the iterator protocol correctly. It keeps calling next() until iteration ends.

That is the most Pythonic answer to the question: instead of checking hasNext(), structure the code so the iteration construct handles exhaustion for you.

Use next With a Default When Needed

Sometimes you do need a one-step look at the next item without raising an exception. In that case, next(iterator, default) is often enough.

python
1values = iter([10, 20])
2
3print(next(values, None))
4print(next(values, None))
5print(next(values, None))

The third call returns None instead of raising StopIteration.

Be careful with sentinels. If None is a valid item in the iterator, use a unique object instead.

python
1sentinel = object()
2item = next(values, sentinel)
3if item is sentinel:
4    print("iterator exhausted")

Implementing a Peekable Wrapper

If your logic truly needs repeated "do we have another item" checks, build a small wrapper that buffers one value.

python
1class Peekable:
2    def __init__(self, iterable):
3        self._iterator = iter(iterable)
4        self._sentinel = object()
5        self._buffer = self._sentinel
6
7    def has_next(self):
8        if self._buffer is self._sentinel:
9            self._buffer = next(self._iterator, self._sentinel)
10        return self._buffer is not self._sentinel
11
12    def __iter__(self):
13        return self
14
15    def __next__(self):
16        if self._buffer is not self._sentinel:
17            item = self._buffer
18            self._buffer = self._sentinel
19            return item
20        item = next(self._iterator, self._sentinel)
21        if item is self._sentinel:
22            raise StopIteration
23        return item
24
25
26it = Peekable([1, 2, 3])
27while it.has_next():
28    print(next(it))

This works, but it is extra machinery. Only use it when the control flow genuinely needs peeking.

Alternatives for Parsing and Stream Logic

A lot of code that seems to need hasNext() can be rewritten more cleanly with one of these patterns:

  • a for loop
  • 'next(iterator, default)'
  • a while True loop with try and except StopIteration
  • 'itertools utilities for chunking or grouping'

For example:

python
1it = iter([1, 2, 3])
2while True:
3    try:
4        item = next(it)
5    except StopIteration:
6        break
7    print(item)

This is closer to the actual iterator protocol than inventing a custom hasNext() convention everywhere.

Common Pitfalls

The biggest mistake is trying to inspect an iterator without consuming it. For many iterators, checking the next item requires actually pulling that item out.

Another issue is using None as a default sentinel when None may be a legitimate iterator value.

Developers also sometimes convert the entire iterator to a list just to see whether items remain. That defeats the purpose of lazy iteration and may waste a lot of memory.

Finally, if you create a custom has_next() wrapper, make sure it preserves the item it peeked. A broken wrapper often consumes elements silently.

Summary

  • Python iterators do not have a built-in hasNext() method.
  • The normal protocol is next() plus StopIteration.
  • Prefer for loops and iterator-friendly patterns over manual availability checks.
  • Use next(iterator, default) for simple one-step fallback behavior.
  • Build a peekable wrapper only when the control flow truly requires it.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.