MODULE 08

Advanced Python

Decorators, Generators, Iterators, Lambda, Higher-Order Functions, Closures & Practical Advanced Python Patterns — explained step by step.

8Major Topics
45Detailed Subtopics
30Coding Questions
30Theory Q&A
TOPIC 01

1. Advanced Python Introduction

1.1 What makes Python advanced?

Advanced Python features help you write shorter, reusable, flexible, and more powerful programs. This module focuses on lambda functions, iterators, generators, decorators, and practical combinations of these concepts.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

1.2 When should you use advanced features?

Use them when they make code clearer, reusable, or efficient. Advanced syntax should not be used only to make code shorter; readability and maintainability are important.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

1.3 Functional thinking

Python supports functional-style programming through functions as objects, lambda expressions, map(), filter(), reduce(), comprehensions, and higher-order functions.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

1.4 Lazy evaluation

Lazy evaluation means producing or calculating values only when they are needed. Generators and iterators are important tools for processing large data efficiently.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.
TOPIC 02

2. Lambda Functions

2.1 What is lambda?

A lambda is a small anonymous function written with the lambda keyword. It can accept arguments and return an expression result.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

2.2 Lambda syntax

The general form is lambda arguments: expression. Unlike def, a lambda normally contains one expression rather than a block of statements.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

2.3 Lambda with sorting

sorted() can receive a key function. A lambda is commonly used to tell Python which value should determine the sorting order.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

2.4 Lambda with map()

map() applies a function to every item in an iterable. A lambda can transform each item.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

2.5 Lambda with filter()

filter() keeps items for which a function returns True. A lambda is useful for expressing the filtering condition.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

2.6 Lambda with reduce()

functools.reduce() repeatedly combines values using a function until one result remains. It should be used when the reduction logic is clear.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.
TOPIC 03

3. Iterators

3.1 What is an iterable?

An iterable is an object that can provide its items one at a time, such as a list, tuple, string, set, dictionary, or range.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

3.2 What is an iterator?

An iterator is an object that remembers its current position and provides the next item through __next__().

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

3.3 iter()

iter() obtains an iterator from an iterable.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

3.4 next()

next() requests the next item from an iterator. When there are no more items, StopIteration is raised.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

3.5 Creating a custom iterator

A class can implement __iter__() and __next__() to define custom iteration behavior.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

3.6 Iterable vs iterator

An iterable can produce an iterator. An iterator maintains iteration state and implements the iterator protocol.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.
TOPIC 04

4. Generators

4.1 What is a generator?

A generator is a convenient way to create an iterator. A generator function uses yield to produce values one at a time.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

4.2 yield vs return

return finishes a function and gives one final result. yield pauses a generator, preserves its state, and resumes it when the next value is requested.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

4.3 Generator execution

The function body does not run completely at generator creation. Each next() call resumes execution until the next yield.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

4.4 Generator expressions

A generator expression looks similar to a comprehension but uses parentheses and produces values lazily.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

4.5 Memory efficiency

Generators avoid creating the entire result collection in memory at once, making them useful for large sequences and streams.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

4.6 Practical generators

Generators are useful for reading large files, producing sequences, processing records, and creating pipelines of transformations.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.
TOPIC 05

5. Decorators

5.1 What is a decorator?

A decorator is a function that receives another function and extends or modifies its behavior without changing the original function's core code.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

5.2 Functions are first-class objects

Python functions can be assigned to variables, passed as arguments, returned from other functions, and stored in collections.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

5.3 Basic decorator

A decorator commonly contains an inner wrapper function, calls the original function, and returns the wrapper.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

5.4 @decorator syntax

The @decorator syntax is shorthand for replacing a function with the decorator's returned function.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

5.5 functools.wraps

functools.wraps helps preserve metadata such as the decorated function's name and docstring.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

5.6 Decorators with arguments

A decorator can inspect or modify function arguments using *args and **kwargs inside its wrapper.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

5.7 Practical decorator uses

Common uses include logging, timing, authentication checks, validation, caching, retries, and access control.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.
TOPIC 06

6. Higher-Order Functions

6.1 Functions as arguments

A function can receive another function as an argument, allowing behavior to be supplied dynamically.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

6.2 Functions returning functions

A function can create and return another function. This is the foundation of closures and many decorator patterns.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

6.3 map()

map(function, iterable) applies a function to each item and returns an iterator.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

6.4 filter()

filter(function, iterable) returns an iterator containing items for which the function is truthy.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

6.5 reduce()

reduce() from functools combines iterable items cumulatively into a single value.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

6.6 Choosing the right tool

Use comprehensions when they are clearer, map/filter when they communicate the transformation or selection clearly, and reduce only when a cumulative reduction is natural.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.
TOPIC 07

7. Closures and Scope

7.1 What is a closure?

A closure is an inner function that remembers values from its enclosing scope even after the outer function has finished.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

7.2 Why closures are useful

Closures can preserve configuration or state without requiring a class. They are useful for factories, callbacks, and decorators.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

7.3 nonlocal

The nonlocal keyword allows an inner function to modify a variable belonging to its nearest enclosing function scope.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

7.4 LEGB

Python resolves names using Local, Enclosing, Global, and Built-in scopes.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

7.5 Closure workflow

The outer function creates a value, defines an inner function that references it, and returns that inner function. Later calls use the remembered value.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.
TOPIC 08

8. Practical Advanced Python Patterns

8.1 Chaining operations

Iterators and generators can be combined so data flows through multiple processing steps without creating unnecessary intermediate lists.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

8.2 Decorator + function reuse

A decorator can add common behavior such as logging to many functions while keeping each business function focused.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

8.3 Generator + file processing

A generator can read a large file line by line and yield only the records needed for the next processing stage.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

8.4 Common mistakes

Avoid deeply nested lambdas, confusing decorators, unnecessary reduce(), generators when a tiny list is clearer, and custom iterators when a normal generator would be simpler.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.

8.5 Readability rule

Advanced Python should make the program easier to maintain. Prefer the simplest feature that clearly solves the problem.

Step-by-step:
  1. Understand the purpose of the advanced feature.
  2. Study the syntax and execution flow.
  3. Run a small example and observe what happens.
  4. Change the input and test the behavior again.
  5. Apply the feature to the related coding problem.
HANDS-ON PRACTICE

30 Coding Questions

Try each problem yourself first, then open the step-by-step solution.

Q01

Create a simple lambda that adds two numbers.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
add = lambda a, b: a + b
print(add(10, 20))
Q02

Use lambda to square every number with map().

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x * x, numbers))
print(squares)
Q03

Use lambda with filter() to keep even numbers.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
numbers = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)
Q04

Sort students by marks using lambda.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
students = [
    ("Ravi", 75),
    ("Anita", 92),
    ("Kiran", 81)
]

result = sorted(students, key=lambda student: student[1])
print(result)
Q05

Use reduce() to calculate the sum of numbers.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
from functools import reduce

numbers = [10, 20, 30, 40]
total = reduce(lambda a, b: a + b, numbers)
print(total)
Q06

Create an iterator from a list.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
numbers = [10, 20, 30]
iterator = iter(numbers)

print(next(iterator))
print(next(iterator))
print(next(iterator))
Q07

Handle StopIteration manually.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
numbers = [10, 20]
iterator = iter(numbers)

try:
    while True:
        print(next(iterator))
except StopIteration:
    print("No more values")
Q08

Create a custom countdown iterator.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
class Countdown:
    def __init__(self, start):
        self.current = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.current <= 0:
            raise StopIteration
        value = self.current
        self.current -= 1
        return value

for number in Countdown(5):
    print(number)
Q09

Create a generator that yields numbers from 1 to 5.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def numbers():
    for i in range(1, 6):
        yield i

for n in numbers():
    print(n)
Q10

Create a generator for even numbers.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def even_numbers(limit):
    for i in range(2, limit + 1, 2):
        yield i

print(list(even_numbers(10)))
Q11

Use next() with a generator.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def values():
    yield "A"
    yield "B"
    yield "C"

g = values()
print(next(g))
print(next(g))
print(next(g))
Q12

Create a generator expression for squares.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
squares = (x * x for x in range(1, 6))

for value in squares:
    print(value)
Q13

Create a generator that reads a file line by line.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def read_lines(filename):
    with open(filename, encoding="utf-8") as file:
        for line in file:
            yield line.strip()

for line in read_lines("data.txt"):
    print(line)
Q14

Create a basic decorator.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def logger(func):
    def wrapper():
        print("Function started")
        func()
        print("Function finished")
    return wrapper

@logger
def greet():
    print("Hello")

greet()
Q15

Create a decorator that accepts arguments.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def logger(func):
    def wrapper(*args, **kwargs):
        print("Calling function")
        result = func(*args, **kwargs)
        print("Function completed")
        return result
    return wrapper

@logger
def add(a, b):
    return a + b

print(add(5, 7))
Q16

Preserve function metadata with functools.wraps.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
from functools import wraps

def logger(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@logger
def greet():
    """Greets the user."""
    print("Hello")

print(greet.__name__)
print(greet.__doc__)
Q17

Create a timing-style decorator.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
import time
from functools import wraps

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        end = time.perf_counter()
        print("Time:", end - start)
        return result
    return wrapper

@timer
def work():
    total = sum(range(100000))
    return total

print(work())
Q18

Create a decorator that checks positive numbers.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
from functools import wraps

def positive_only(func):
    @wraps(func)
    def wrapper(x):
        if x <= 0:
            raise ValueError("Number must be positive")
        return func(x)
    return wrapper

@positive_only
def square(x):
    return x * x

print(square(5))
Q19

Use map() to convert strings to uppercase.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
words = ["python", "sql", "power bi"]
result = list(map(str.upper, words))
print(result)
Q20

Use filter() to select names longer than four characters.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
names = ["Ravi", "Anita", "Kiran", "Suresh"]
result = list(filter(lambda name: len(name) > 4, names))
print(result)
Q21

Use reduce() to calculate a product.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
from functools import reduce

numbers = [2, 3, 4, 5]
product = reduce(lambda a, b: a * b, numbers)
print(product)
Q22

Pass a function as an argument.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def apply_operation(a, b, operation):
    return operation(a, b)

def multiply(x, y):
    return x * y

print(apply_operation(6, 7, multiply))
Q23

Return a function from another function.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def multiplier(factor):
    def multiply(number):
        return number * factor
    return multiply

double = multiplier(2)
print(double(10))
Q24

Create a closure with nonlocal state.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def counter():
    count = 0

    def increment():
        nonlocal count
        count += 1
        return count

    return increment

c = counter()
print(c())
print(c())
print(c())
Q25

Create a decorator factory with a custom message.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
from functools import wraps

def message(text):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print(text)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@message("Starting task")
def task():
    print("Task running")

task()
Q26

Build a generator pipeline for even squares.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def numbers():
    for i in range(1, 11):
        yield i

evens = (x for x in numbers() if x % 2 == 0)
squares = (x * x for x in evens)

print(list(squares))
Q27

Build a reusable validation decorator.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
from functools import wraps

def require_name(func):
    @wraps(func)
    def wrapper(name):
        if not name.strip():
            raise ValueError("Name cannot be empty")
        return func(name)
    return wrapper

@require_name
def greet(name):
    return f"Hello {name}"

print(greet("Naveen"))
Q28

Build a custom iterator for a range.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
class NumberRange:
    def __init__(self, start, stop):
        self.current = start
        self.stop = stop

    def __iter__(self):
        return self

    def __next__(self):
        if self.current >= self.stop:
            raise StopIteration
        value = self.current
        self.current += 1
        return value

for n in NumberRange(1, 5):
    print(n)
Q29

Create a generator for Fibonacci numbers.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
def fibonacci(count):
    a, b = 0, 1
    for _ in range(count):
        yield a
        a, b = b, a + b

print(list(fibonacci(10)))
Q30

Create a decorator that counts function calls.

Step 1: Identify the advanced Python concept required.
Step 2: Write the smallest clear implementation of the concept.
Step 3: Run the code and trace the execution flow.
Step 4: Modify the example and verify the behavior.
from functools import wraps

def count_calls(func):
    calls = 0

    @wraps(func)
    def wrapper(*args, **kwargs):
        nonlocal calls
        calls += 1
        print("Call number:", calls)
        return func(*args, **kwargs)

    return wrapper

@count_calls
def greet(name):
    print("Hello", name)

greet("A")
greet("B")
greet("C")
KNOWLEDGE CHECK

30 Theory Questions with Answers

Use these for revision, interviews, and classroom practice.

Q01

What is an advanced Python feature?

Answer: It is a language or library feature that helps solve problems with more flexible, reusable, efficient, or expressive code.
Q02

What is a lambda function?

Answer: A lambda is a small anonymous function written with lambda and normally containing a single expression.
Q03

What is the syntax of lambda?

Answer: The general syntax is lambda arguments: expression.
Q04

Can a lambda contain multiple statements?

Answer: A normal lambda is limited to one expression, so complex multi-statement logic should usually use def.
Q05

What is map()?

Answer: map() applies a function to each item in an iterable and returns an iterator.
Q06

What is filter()?

Answer: filter() returns an iterator containing items for which the supplied function returns a truthy result.
Q07

What is reduce()?

Answer: reduce() repeatedly combines iterable elements using a function until a single accumulated result remains.
Q08

What is an iterable?

Answer: An iterable is an object that can provide its elements one at a time, such as a list or string.
Q09

What is an iterator?

Answer: An iterator is an object that maintains iteration state and provides the next item through __next__().
Q10

What does iter() do?

Answer: iter() obtains an iterator from an iterable.
Q11

What does next() do?

Answer: next() requests the next value from an iterator and raises StopIteration when values are exhausted.
Q12

What is StopIteration?

Answer: It is the exception used to signal that an iterator has no more values.
Q13

What is a custom iterator?

Answer: It is a programmer-defined object implementing the iterator protocol, normally __iter__() and __next__().
Q14

What is a generator?

Answer: A generator is a convenient way to create an iterator, usually by using yield inside a generator function.
Q15

What is yield?

Answer: yield produces a value and pauses the generator while preserving its execution state for the next request.
Q16

What is the difference between yield and return?

Answer: return finishes the function; yield pauses a generator and allows it to continue later.
Q17

What is a generator expression?

Answer: It is a compact lazy expression using parentheses, similar to a comprehension but producing values on demand.
Q18

Why are generators memory efficient?

Answer: They produce values one at a time instead of storing the complete sequence in memory.
Q19

What is a decorator?

Answer: A decorator is a callable that receives another function or callable and returns a modified or extended callable.
Q20

Why use decorators?

Answer: They allow common behavior such as logging, timing, validation, caching, and authorization to be reused without duplicating code.
Q21

What does @decorator mean?

Answer: It is shorthand syntax that applies a decorator to the function defined immediately below it.
Q22

What is functools.wraps?

Answer: wraps helps a decorator preserve metadata from the original function, such as its name and docstring.
Q23

What are *args and **kwargs in a decorator?

Answer: *args collects positional arguments and **kwargs collects keyword arguments so the wrapper can support flexible function signatures.
Q24

What is a higher-order function?

Answer: A higher-order function accepts another function as an argument, returns a function, or both.
Q25

What is a closure?

Answer: A closure is an inner function that remembers variables from its enclosing scope.
Q26

What does nonlocal do?

Answer: nonlocal allows an inner function to modify a variable from its nearest enclosing function scope.
Q27

What is LEGB?

Answer: LEGB describes Python's name lookup order: Local, Enclosing, Global, and Built-in.
Q28

When should you prefer a normal function over lambda?

Answer: Use def when logic is complex, needs multiple statements, needs documentation, or deserves a meaningful reusable name.
Q29

When are generators useful?

Answer: They are useful for large sequences, file processing, streaming data, pipelines, and situations where values should be produced lazily.
Q30

What is the main rule for using advanced Python?

Answer: Choose advanced features when they improve clarity, reuse, or efficiency; do not sacrifice readability just to make code shorter.