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!