Python Iterators And Generators

Python provides two powerful concepts, iterators and generators, for handling sequences of data. They make your code more efficient, especially when dealing with large data sets or infinite sequences. In this tutorial, we’ll explore what iterators and generators are and how to use them with practical examples.

1. What is an Iterator?

An iterator is an object that allows you to traverse through all the elements in a collection (like lists or tuples) one at a time. It follows two key methods:

  • __iter__(): Returns the iterator object itself.
  • __next__(): Returns the next element in the sequence. Raises StopIteration when there are no more elements.

Example: Creating a Custom Iterator

class MyIterator:
    def __init__(self, numbers):
        self.numbers = numbers
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index < len(self.numbers):
            result = self.numbers[self.index]
            self.index += 1
            return result
        else:
            raise StopIteration

# Using the custom iterator
my_iter = MyIterator([1, 2, 3, 4, 5])
for num in my_iter:
    print(num)

Try It Now

2. What is a Generator?

A generator is a special type of iterator that is easier to create. Instead of using __iter__() and __next__() methods, you use a function with the yield keyword. Generators are more memory-efficient than iterators because they generate values on the fly.

Example: Creating a Generator

def my_generator():
    yield 1
    yield 2
    yield 3

# Using the generator
for value in my_generator():
    print(value)

Try It Now

3. Differences Between Iterators and Generators

Feature Iterator Generator
Definition An object with __iter__() and __next__() methods. A function that uses yield to return values one at a time.
Memory Usage May require more memory for large sequences. More memory-efficient as values are generated on the fly.
Complexity Requires implementing two methods. Easier to create with the yield keyword.

4. Generator Expressions

Generator expressions are a concise way to create generators. They are similar to list comprehensions but use parentheses instead of square brackets.

Example: Generator Expression

squared_numbers = (x * x for x in range(5))

for num in squared_numbers:
    print(num)

Try It Now

5. Advantages of Generators

  • Memory Efficiency: Generate values on the fly without storing the entire sequence in memory.
  • Lazy Evaluation: Values are generated only when needed.
  • Improved Performance: Useful for large data sets or infinite sequences.

6. Practical Use Cases for Generators

  • Reading large files line by line.
  • Generating infinite sequences.
  • Streaming data in real-time.

Example: Reading a File Line by Line with a Generator

def read_file():
    with open('example.txt', 'r') as file:
        for line in file:
            yield line.strip()

# Using the file generator
for line in read_file():
    print(line)

Try It Now

Conclusion

Iterators and generators are powerful tools in Python that help you handle data sequences efficiently. While iterators give you control over how to iterate, generators provide a simpler and more memory-efficient way to achieve the same results.