What is a Generator

1. Iterable and Iterator Classes

# Iterable class
class MyRange:
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __iter__(self):
        return MyIterator(self)

# Iterator class
class MyIterator:
    def __init__(self, iterable_obj):
        self.iterable = iterable_obj

    def __iter__(self):
        return self

    def __next__(self):
        if self.iterable.start >= self.iterable.end:
            raise StopIteration

        current = self.iterable.start
        self.iterable.start += 1
        return current

Explanation: The MyRange class is an iterable, and the MyIterator class is an iterator. Iterators are used to iterate over elements in an iterable. The __iter__ method returns an iterator, and the __next__ method is responsible for fetching the next element.

2. Example Usage of Iterable and Iterator

# Example usage of iterable and iterator
for i in MyRange(1, 5):
    print(i)

Explanation: Demonstrates the use of the custom iterable and iterator to iterate over a range of numbers.

3. Simple Generator Function

# Simple generator function
def gen_demo():
    yield "first statement"
    yield "second statement"
    yield "third statement"

Explanation: The gen_demo function is a generator that uses the yield keyword to produce a sequence of values. Each call to next() on the generator resumes execution from where it left off.

4. Example Usage of Generator

# Example usage of generator
gen = gen_demo()
for i in gen:
    print(i)

Explanation: Illustrates how to use the generator function, yielding and printing each value.

5. Generator Function for Squares

# Generator function to generate squares
def square(num):
    for i in range(1, num + 1):
        yield i ** 2

Explanation: The square function generates squares of numbers up to a given limit using the yield keyword.

6. Example Usage of Square Generator

# Example usage of square generator
gen = square(10)
for i in gen:
    print(i)

Explanation: Demonstrates the use of the square generator to print the squares of numbers up to 10.

7. Generator Function for Custom Range

# Generator function for custom range
def custom_range(start, end):
    for i in range(start, end):
        yield i

Explanation: Defines a generator function that yields values within a specified range.

8. Example Usage of Custom Range Generator

# Example usage of custom range generator
for i in custom_range(15, 26):
    print(i)

Explanation: Uses the custom range generator to print values within the specified range.

9. Generator Expression

# Generator expression
L = [i ** 2 for i in range(1, 101)]
gen = (i ** 2 for i in range(1, 101))

Explanation: Shows the difference between list comprehension and a generator expression.

10. Example Usage of Generator Expression

# Example usage of generator expression
for i in gen:
    print(i)

Explanation: Prints the squares of numbers from 1 to 100 using the generator expression.

11. Practical Example: Image Data Reader

# Practical example of using a generator for reading image data
import os
import cv2

def image_data_reader(folder_path):
    for file in os.listdir(folder_path):
        f_array = cv2.imread(os.path.join(folder_path, file))
        yield f_array

# Example usage of image data generator
gen = image_data_reader('data path')
next(gen)
next(gen)

Explanation: Illustrates the practical use of a generator to read image data efficiently.

12. Benefits of Using a Generator

# Benefits of using a generator
# 1. Ease of Implementation
class MyRange:
    # ... (same as above)

# 2. Memory Efficient
L = [x for x in range(100000)]
gen = (x for x in range(100000))
import sys
print('Size of L in memory:', sys.getsizeof(L))
print('Size of gen in memory:', sys.getsizeof(gen))

Explanation: Highlights the benefits of using generators, such as ease of implementation and memory efficiency.

13. Representing Infinite Streams

# 3. Representing Infinite Streams
def all_even():
    n = 0
    while True:
        yield n
        n += 2

even_num_gen = all_even()
next(even_num_gen)
next(even_num_gen)

Explanation: Shows how generators can represent infinite streams of data.

14. Chaining Generators

# 4. Chaining Generators
def fibonacci_numbers(nums):
    x, y = 0, 1
    for _ in range(nums):
        x, y = y, x + y
        yield x

def square(nums):
    for num in nums:
        yield num ** 2

print(sum(square(fibonacci_numbers(10))))

Explanation: Demonstrates the ability to chain generators for more complex computations.

.

9 Replies to “Python Generators”

Leave a Reply

Your email address will not be published. Required fields are marked *