Python3 Iterators and Generators
Iterators
Iteration is one of the most powerful features of Python and is a way to access elements of a collection.
An iterator is an object that can remember the traversal position.
The iterator object starts accessing elements from the first element of the collection until all elements have been accessed. Iterators can only move forward and not backward.
There are two basic methods for iterators: iter() and next().
String, list, or tuple objects can be used to create an iterator:
Example (Python 3.0+)
>>> list=[1,2,3,4]
>>> it = iter(list) # Create an iterator object
>>> print(next(it)) # Output the next element of the iterator
1
>>> print(next(it))
2
>>>
Iterator objects can be traversed using a regular for statement:
Example (Python 3.0+)
#!/usr/bin/python3
list=[1,2,3,4]
it = iter(list) # Create an iterator object
for x in it:
print(x, end=" ")
Executing the above program, the output is:
1 2 3 4
You can also use the next() function:
Example (Python 3.0+)
#!/usr/bin/python3
import sys # Import the sys module
list=[1,2,3,4]
it = iter(list) # Create an iterator object
while True:
try:
print(next(it))
except StopIteration:
sys.exit()
Executing the above program, the output is:
1
2
3
4
Creating an Iterator
To use a class as an iterator, you need to implement the methods __iter__() and __next__() within the class.
If you are familiar with object-oriented programming, you know that classes have a constructor. Python's constructor is __init__(), which executes when the object is initialized.
For more details, refer to: Python3 Object-Oriented Programming
The __iter__() method returns a special iterator object that implements the __next__() method and signals the end of iteration by raising the StopIteration exception.
The __next__() method (next() in Python 2) returns the next iterator object.
Create an iterator that returns numbers, starting with 1, and each sequence will increase by one:
Example (Python 3.0+)
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
Executing the output is:
1
2
3
4
5
StopIteration
The StopIteration exception is used to signal the completion of an iteration to prevent infinite loops. In the __next__() method, we can set the StopIteration exception to be raised after a specified number of iterations.
Stop execution after 20 iterations:
Example (Python 3.0+)
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration
myclass = MyNumbers()
myiter = iter(myclass)
for x in myiter:
print(x)
Executing the output is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Generators
In Python, a function that uses the yield keyword is called a generator.
Unlike regular functions, a generator is a function that returns an iterator and can be used for iteration. Simply put, a generator is an iterator.
During the execution of a generator function, each time yield is encountered, the function pauses and saves all its current state, returning the value of yield. The next execution of next() will continue from the current position. Calling a generator function returns an iterator object.
The following example uses yield to implement the Fibonacci sequence:
Example (Python 3.0+)
#!/usr/bin/python3
import sys
def fibonacci(n): # Generator function - Fibonacci
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f is an iterator, returned by the generator
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
Executing the above program produces the following output:
0 1 1 2 3 5 8 13 21 34 55