Sitemap

DS in Python 1: Iterators

5 min readSep 4, 2026

--

When working with Python, we often process collections such as lists, tuples, dictionaries, files, NumPy arrays, or even huge datasets.

Consider this:

numbers = [10, 20, 30, 40]
for number in numbers:
print(number)

'''
Output:
10
20
30
40
'''

This looks simple. But have you ever wondered:

How does Python know which element comes next?

The answer is: Iterators.

Iterators are one of the fundamental concepts behind Python’s for loops, generators, file processing, and many memory-efficient Data Science workflows.

1. What Is an Iterator?

An iterator is an object that allows us to access elements one at a time.

Instead of loading and processing everything simultaneously, an iterator gives us the next value whenever we ask for it.

For example:

numbers = [10, 20, 30, 40]

iterator = iter(numbers)
print(next(iterator))
print(next(iterator))
print(next(iterator))

'''Output:
10
20
30
'''

Each call to next() moves the iterator forward.

numbers -> [10, 20, 30, 40]

next()
↓
10
next()
↓
20
next()
↓
30

An important point is that the iterator remembers its current position.

After consuming 10, Python knows that the next value should be 20.

2. Iterable vs Iterator

This is one of the most important concepts to understand.

Many people confuse an iterable with an iterator.

What is an Iterable?

An iterable is an object that contains a collection of values and can be converted into an iterator.

Common iterables include:

list
tuple
string
dictionary
set
file
range

Example:

numbers = [1, 2, 3, 4]

The list is an iterable.

But we cannot directly use next() on a list:

numbers = [1, 2, 3]
next(numbers)

This raises an error:

TypeError: 'list' object is not an iterator

We first need to create an iterator.

numbers = [1, 2, 3]
iterator = iter(numbers)
print(next(iterator))

#Output:
#1

What is an Iterator?

An iterator is an object that:

  1. Keeps track of its current position
  2. Returns the next item using next()
  3. Raises StopIteration when no elements remain

Example:

numbers = [10, 20, 30]

iterator = iter(numbers)
print(next(iterator))
print(next(iterator))
print(next(iterator))

'''OUTPUT:
10
20
30
'''

Now there are no values left.

print(next(iterator))

Python raises:

StopIteration

The relationship can be visualized like this:

Iterable (list, dictionary, ... )
|
| iter() {Convert the iterable to iterator using iter()}
v
Iterator
|
| next() {Use this next() function to access one element at a time}
v
Item 1 → Item 2 → Item 3 → StopIteration

3. The iter() Function

Python provides the iter() function to convert an iterable to an iterator

numbers = [10, 20, 30]

iterator = iter(numbers)
print(iterator) # 10

Another example using a string:

text = "DATA"
iterator = iter(text)
print(next(iterator)) # D
print(next(iterator)) # A

Anything which is an iterable can be converted to an iterator using iter()

4. The next() function

The next() function retrieves the next item from an iterator.

numbers = [100, 200, 300]

iterator = iter(numbers)
print(next(iterator)) #100
print(next(iterator)) #200
print(next(iterator)) #300

Conceptually:

Iterator initially
[100, 200, 300]
↑
next()
--------------------------
After first next()
[100, 200, 300]
↑
next()
--------------------------
After second next()
[100, 200, 300]
↑
next()

Once every item has been consumed, Python raises StopIteration.

5. How does a ‘for’ Loop use an Iterator?

When we write:

numbers = [10, 20, 30]

for number in numbers:
print(number)

Python internally does something similar to this:

iterator = iter(numbers)

while True:
try:
number = next(iterator)
print(number)
except StopIteration:
break

So:

for number in numbers:
print(number)

is essentially Python automatically doing:

iter()
↓
next()
↓
next()
↓
next()
↓
StopIteration
↓
Stop

This is why for loops can work with lists, tuples, strings, files, generators, and many other objects.

6. The Iterator Protocol

For an object to behave as an iterator, it must follow Python’s iterator protocol.

An iterator should implement two methods:

__iter__()

This method returns the iterator object.

__next__()

This method returns the next value.

Get Abhishek Jain’s stories in your inbox

Join Medium for free to get updates from this writer.

When no more values are available, it should raise: StopIteration

Conceptually:

class MyIterator:

def __iter__(self):
return self
def __next__(self):
# Return next item
# If finished:
raise StopIteration

7. Creating a Custom Iterator

Let’s create our own iterator.

Suppose we want an iterator that returns numbers from 1 to 5.

class NumberIterator:

def __init__(self):
self.current = 1
def __iter__(self):
return self
def __next__(self):
if self.current > 5:
raise StopIteration
value = self.current
self.current += 1
return value

Now we can use it.

iterator = NumberIterator()

print(next(iterator)) #1
print(next(iterator)) #2
print(next(iterator)) #3

Or use it inside a for loop:

for number in NumberIterator():
print(number)

8. Iterable Object vs Iterator Object

We can create a custom iterable and a separate iterator.

For example:

class NumberCollection:
def __init__(self, numbers):
self.numbers = numbers

def __iter__(self):
return NumberIterator(self.numbers)


class NumberIterator:
def __init__(self, numbers):
self.numbers = numbers
self.index = 0

def __iter__(self):
return self

def __next__(self):
if self.index < len(self.numbers):
value = self.numbers[self.index]
self.index += 1
return value

raise StopIteration


collection = NumberCollection([10, 20, 30])

for number in collection:
print(number)

#10
#20
#30
Press enter or click to view image in full size

An iterale is an object that can return an iterator

An iterable implements __iter__() and can return an iterator. An iterator implements both __iter__() and __next__().

Type 1: Sequence Iterators

Sequences such as lists, tuples, strings, and ranges can produce iterators.

List Iterator

numbers = [10, 20, 30]
iterator = iter(numbers)
print(next(iterator)) #10

Tuple Iterator

values = (1, 2, 3)
iterator = iter(values)
print(next(iterator)) # 1

String Iterator

text = "AI"
iterator = iter(text)
print(next(iterator)) #A
print(next(iterator)) #I

Range Iterator

iterator = iter(range(1, 5))

for value in iterator:
print(value)
#1
#2
#3
#4

Infinite Iterators

Some iterators can theoretically generate values forever.

For example, using itertools.count():

import itertools

counter = itertools.count()
print(next(counter)) #0
print(next(counter)) #1
print(next(counter)) #2

It can continue:

3
4
5
...

Another example:

counter = itertools.count(start=10, step=5)
for _ in range(5):
print(next(counter))

'''
10
15
20
25
30
'''

Infinite iterators should be used carefully.

This will never stop:

for value in itertools.count():
print(value)

A Simple Example to Remember

Here’s perhaps the simplest way to understand an iterator:

numbers = [10, 20, 30]

iterator = iter(numbers)
while True:
try:
number = next(iterator)
print(number)
except StopIteration:
break

Output:

10
20
30

The iterator remembers its position.

After returning 10, it knows that 20 is next.

After returning 20, it knows that 30 is next.

After returning 30, it knows that there are no more values.

Advantages of Iterators

Iterators provide several important benefits.

1. Memory Efficient

They allow us to process values one at a time instead of storing everything in memory.

2. Good for Large Data

They are particularly useful when working with large files, datasets, or streams.

3. Lazy Evaluation

Values can be produced only when they are needed.
This is called lazy evaluation.

4. Simple Looping

Python’s for loop works naturally with iterators.

5. Reusable Concept

The same iteration mechanism works with many different data sources.

One Important Point: Iterators Are Usually Exhausted

An iterator moves forward.

For example:

numbers = [10, 20, 30]

iterator = iter(numbers)
print(list(iterator)) # [10, 20, 30]

If you try to use the same iterator again:

print(list(iterator))

you’ll get:

[]

Why?

Because the iterator has already reached the end.

If you want to iterate again, we will have to create a new iterator:

iterator = iter(numbers)
print(list(iterator)) # [10, 20, 30]

--

--