Generators and iterators are powerful concepts in Python that allow for efficient and memory-friendly iteration over a sequence of values. They enable lazy evaluation, generating values on-the-fly rather than generating all values at once.

Let’s explore generators and iterators in Python:

# Creating a generator function
def countdown(n):
    while n > 0:
        yield n
        n -= 1

# Using a generator function
for num in countdown(5):
    print(num)

# Creating an iterator using iter() and next()
my_list = [1, 2, 3, 4, 5]
my_iter = iter(my_list)

# Using the iterator
print(next(my_iter))  # 1
print(next(my_iter))  # 2
print(next(my_iter))  # 3
print(next(my_iter))  # 4
print(next(my_iter))  # 5

# Creating an iterator class
class MyIterator:
    def __init__(self, my_list):
        self.my_list = my_list
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.my_list):
            raise StopIteration
        value = self.my_list[self.index]
        self.index += 1
        return value

# Using the iterator class
my_list = [1, 2, 3, 4, 5]
my_iter = MyIterator(my_list)

for num in my_iter:
    print(num)

Explanation:

  • Generators are created using generator functions, defined with the yield keyword. The yield statement allows the function to yield a value and temporarily suspend its execution. The generator function can be iterated over using a for loop or by manually calling the next() function on the generator object.
  • Iterators can be created using the iter() function, which takes an iterable object as an argument and returns an iterator. The next() function is used to retrieve the next element from the iterator. When there are no more elements, the StopIteration exception is raised.
  • Iterators can also be created by defining a class that implements the __iter__() and __next__() methods. The __iter__() method returns the iterator object itself, and the __next__() method returns the next value from the iterator or raises StopIteration when there are no more values.

Now it’s time for a practical task:

Task 18:

Write a generator function called fibonacci() that generates the Fibonacci sequence. The function should yield each Fibonacci number one at a time. Test the generator by iterating over it and printing the first 10 Fibonacci numbers.

Once you’ve completed the task, you can proceed to the next lesson.