Home » Python Iterators Tutorial with Examples

Python Iterators Tutorial with Examples

In Python, an iterator is an object that allows you to traverse through all the elements in a collection, such as a list or a tuple, one at a time.

Iterators provide a memory-efficient way to loop through large datasets or collections because they don’t load everything into memory at once.

In this tutorial, you’ll learn:

What are iterators?

How iterators work in Python
Creating an iterator using the iter() and next() functions
Building custom iterators with classes
Using __iter__() and __next__() methods
Practical examples of iterators

1. What Are Iterators?

An iterator is an object that implements the iterator protocol, which consists of the methods __iter__() and __next__(). It represents a sequence of values that can be iterated over.

Iterators are useful when working with large datasets, as they only compute the next item when requested, rather than loading all the data into memory at once.

2. How Iterators Work in Python

Example: Iterating Over a List

In Python, many built-in objects like lists, tuples, sets, and dictionaries are iterable, which means they can return an iterator object. You can loop over them using a for loop:

numbers = [1, 2, 3, 4, 5]

for number in numbers:
    print(number)

Output:

1
2
3
4
5

In this example, Python automatically creates an iterator behind the scenes to traverse the list.

3. Creating an Iterator Using iter() and next()

You can manually create an iterator from an iterable using the iter() function and fetch items one at a time using the next() function.

Example: Using iter() and next()

numbers = [10, 20, 30, 40, 50]

# Create an iterator object
numbers_iter = iter(numbers)

# Accessing elements using next()
print(next(numbers_iter))  #

Output:
10
print(next(numbers_iter)) #

Output:
20
print(next(numbers_iter)) #

Output:
30

Output:

10
20
30

The next() function retrieves the next value in the sequence. Once the iterator reaches the end of the collection, it raises a StopIteration exception.

try:
    print(next(numbers_iter))
    print(next(numbers_iter))
    print(next(numbers_iter))  # This will raise StopIteration
except StopIteration:
    print("End of iterator")

Output:

40
50
End of iterator

4. Building Custom Iterators with Classes

You can create custom iterator objects by defining a class that implements the __iter__() and __next__() methods.

__iter__(): This method should return the iterator object itself and is usually implemented as return self.
__next__(): This method returns the next value from the iterator. If there are no more items, it should raise a StopIteration exception.

Example: Creating a Custom Iterator

Let’s create a custom iterator that generates squares of numbers up to a given limit.

class SquareIterator:
    def __init__(self, limit):
        self.limit = limit
        self.current = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.current > self.limit:
            raise StopIteration
        result = self.current ** 2
        self.current += 1
        return result

# Create an instance of the iterator
squares = SquareIterator(5)

# Using a for loop to iterate over the custom iterator
for square in squares:
    print(square)

Output:

1
4
9
16
25

In this example, the SquareIterator class generates squares of numbers from 1 to a given limit (5 in this case). The iterator stops when StopIteration is raised.

5. Using __iter__() and __next__() Methods

To dive deeper into iterators, let’s break down the two key methods:

__iter__(): This method returns the iterator object itself. It allows the object to be used in contexts where iterables are required, such as in a for loop.

__next__(): This method returns the next value from the iterator each time it’s called. Once all values have been returned, this method raises StopIteration to signal that the iteration has finished.

Example: Fibonacci Sequence with a Custom Iterator

Here’s an example of creating a custom iterator that generates the Fibonacci sequence:

class FibonacciIterator:
    def __init__(self, max_count):
        self.max_count = max_count
        self.num1, self.num2 = 0, 1
        self.count = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.count >= self.max_count:
            raise StopIteration
        result = self.num1
        self.num1, self.num2 = self.num2, self.num1 + self.num2
        self.count += 1
        return result

# Create a Fibonacci iterator for 7 numbers
fibonacci = FibonacciIterator(7)

# Iterating over Fibonacci sequence
for number in fibonacci:
    print(number)

Output:

0
1
1
2
3
5
8

In this example, the FibonacciIterator class generates the first n numbers of the Fibonacci sequence.

6. Practical Examples of Iterators

Example 1: Reading Large Files Line by Line

Iterators are useful when working with large files because they allow you to read one line at a time without loading the entire file into memory.

def file_reader(file_path):
    with open(file_path, 'r') as file:
        for line in file:
            yield line.strip()

# Using the generator to read a file
for line in file_reader("large_file.txt"):
    print(line)

This is an efficient way to process large files where memory usage needs to be minimized.

Example 2: Infinite Sequence Iterator

You can create an iterator that generates an infinite sequence of numbers, though you must be careful to break the iteration manually.

class InfiniteNumbers:
    def __init__(self):
        self.number = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.number += 1
        return self.number

# Create an infinite iterator
infinite_numbers = InfiniteNumbers()

# Using a loop to get the first 5 numbers
for i in range(5):
    print(next(infinite_numbers))

Output:

1
2
3
4
5

In this case, the iterator will keep producing numbers indefinitely. You can use conditions or limits in your loop to stop the iteration.

Example 3: Countdown Iterator

You can create an iterator that counts down from a certain number to zero.

class Countdown:
    def __init__(self, start):
        self.current = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < 0:
            raise StopIteration
        result = self.current
        self.current -= 1
        return result

# Create a countdown iterator starting at 5
countdown = Countdown(5)

# Using a for loop to iterate through the countdown
for number in countdown:
    print(number)

Output:

5
4
3
2
1
0

This is a simple iterator that counts down to zero and stops.

Conclusion

Python iterators provide a memory-efficient way to handle sequences of data. Here’s a summary of what you’ve learned:

You can manually create an iterator using the iter() and next() functions.
Iterators implement the __iter__() and __next__() methods.
Custom iterators can be built using classes, allowing you to define how data is iterated over.
Iterators are useful for working with large datasets, reading files line by line, generating infinite sequences, and more.

By mastering iterators, you can create efficient, scalable programs that handle large amounts of data seamlessly!

You may also like

Leave a Comment

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More