+91 9873530045
admin@learnwithfrahimcom
Mon - Sat : 09 AM - 09 PM

Day 7: Iterators, Generators, and Decorators


Step 1: Iterators

Iterators allow sequential access to elements in a collection.

numbers = [1, 2, 3] # a list of numbers
it = iter(numbers) # create an iterator object from the list
print(next(it)) # prints 1, moves pointer to next element
print(next(it)) # prints 2
print(next(it)) # prints 3

Real-life Example: Reading lines from a large log file:

# Open a large log file and read line by line
with open("system.log", "r") as f:
  lines = iter(f) # create iterator over file lines
  for i in range(5): # print first 5 lines
    print(next(lines).strip())

Step 2: Custom Iterators

Create your own iterator by implementing __iter__() and __next__().

class Counter:
  def __init__(self, low, high):
    self.current = low
    self.high = high

  def __iter__(self):
    return self

  def __next__(self):
    if self.current > self.high:
      raise StopIteration
    else:
      self.current += 1
      return self.current - 1

for num in Counter(1, 5):
  print(num)

Real-life Example: Paginated API request:

class PageIterator:
  def __init__(self, pages):
    self.pages = pages
    self.index = 0

  def __iter__(self):
    return self

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

pages = ["Page1 data", "Page2 data", "Page3 data"]
for page in PageIterator(pages):
  print(page)

Step 3: Generators

Generators yield values lazily using yield, saving memory for large datasets.

def my_generator(n):
  for i in range(n):
    yield i

for val in my_generator(5):
  print(val)

Real-life Example: Streaming sensor data:

def sensor_stream(n):
  """Simulate reading sensor values""
  for i in range(n):
    yield f"Sensor reading {i}: {i*0.5}"

for reading in sensor_stream(5):
  print(reading)

Step 4: Generator Expressions

Compact way to create generators similar to list comprehensions.

squares = (x*x for x in range(5))
for val in squares:
  print(val)

Real-life Example: Calculating squared values of user IDs:

user_ids = range(1, 1000000)
squared_ids = (uid*uid for uid in user_ids)
for i, val in enumerate(squared_ids):
  if i < 5: # just print first 5 to test
    print(val)

Step 5: Decorators

Decorators modify or enhance functions without changing their code.

def decorator(func):
  def wrapper():
    print("Before function")
    func()
    print("After function")
  return wrapper

@decorator
def say_hello():
  print("Hello!")

say_hello()

Real-life Example: Logging function calls:

def log_calls(func):
  def wrapper():
    print(f"Function {func.__name__} started")
    func()
    print(f"Function {func.__name__} ended")
  return wrapper

@log_calls
def process_data():
  print("Processing data...")

process_data()

Step 6: Decorators with Arguments

def repeat(n):
  def decorator(func):
    def wrapper():
      for _ in range(n):
        func()
    return wrapper
  return decorator

@repeat(3)
def say_hi():
  print("Hi!")

say_hi()

Real-life Example: Retry network requests automatically:

import random
def retry(n):
  def decorator(func):
    def wrapper():
      for _ in range(n):
        try:
          func()
          break
        except Exception as e:
          print("Retrying due to:", e)
    return wrapper
  return decorator

@retry(3)
def fetch_data():
  if random.random() < 0.7:
    raise Exception("Network Error")
  print("Data fetched successfully")

fetch_data()

Step 7: PyCharm Project Layout

IterGenDecorators
├── iterators_demo.py
├── generators_demo.py
└── decorators_demo.py
# Example: generators_demo.py
def squares(n):
  """Yield square numbers from 0 to n-1"""
  for i in range(n):
    yield i*i

for val in squares(5):
  print(val)

Step 8: Tips & Best Practices

  • Use iterators and generators for memory-efficient loops.
  • Generators are ideal for streaming data or large sequences.
  • Decorators improve code reuse and readability.
  • Keep decorator logic simple and document it.
  • Test custom iterators carefully to avoid infinite loops.
✔ End of Day 7 – You now understand Iterators, Generators, and Decorators in Python with full real-life examples ready for practical use!