Quiz#
This quiz covers the key concepts from Lecture 5: Advanced Functions,
including programming paradigms, first-class functions, lambda expressions,
closures, callables, decorators, functools.wraps, stacking decorators,
decorators with arguments, and functools.partial.
Note
Instructions:
Answer all questions to the best of your ability.
Multiple choice questions have exactly one correct answer.
True/False questions require you to determine if the statement is correct.
Essay questions require short written responses (2-4 sentences).
Click the dropdown after each question to reveal the answer.
Multiple Choice#
Question 1
What is the output of the following code?
def make_multiplier(n):
return lambda x: x * n
double = make_multiplier(2)
print(double(5))
5102TypeError
Answer
B – 10
make_multiplier(2) returns a lambda that multiplies its argument by 2. Calling double(5) evaluates 5 * 2 = 10.
Question 2
Which of the following is NOT a valid use of a lambda?
sorted(items, key=lambda x: x[1])lambda x, y: x + ylambda x: if x > 0: return xlist(map(lambda x: x**2, [1, 2, 3]))
Answer
C – lambda x: if x > 0: return x
Lambdas can only contain a single expression. if/return statements are not allowed. Conditional expressions (x if x > 0 else 0) are allowed, but statement-based if blocks are not.
Question 3
What is the output of the following code?
def outer():
count = 0
def inner():
nonlocal count
count += 1
return count
return inner
f = outer()
print(f(), f(), f())
1 1 11 2 30 1 2NameError
Answer
B – 1 2 3
outer() creates a closure. Each call to f() increments the captured count variable via nonlocal. The three calls produce 1, 2, and 3.
Question 4
What does the @ syntax do in the following code?
@my_decorator
def my_function():
pass
It calls
my_functionand passes the result tomy_decorator.It is equivalent to
my_function = my_decorator(my_function).It creates a new class called
my_decorator.It passes
my_decoratoras an argument tomy_function.
Answer
B – It is equivalent to my_function = my_decorator(my_function).
The @decorator syntax is syntactic sugar. Python calls the decorator with the function as its argument and replaces the function with the return value.
Question 5
What is the purpose of functools.wraps?
It makes a function run faster.
It copies the original function’s metadata (name, docstring) onto the wrapper.
It prevents a function from being decorated.
It automatically adds type hints to the wrapper function.
Answer
B – It copies the original function’s metadata (name, docstring) onto the wrapper.
Without @wraps(func), the wrapper replaces the original function’s __name__, __doc__, and other attributes. functools.wraps preserves these for introspection and debugging.
Question 6
What is the output of the following code?
from functools import partial
def power(base, exponent):
return base ** exponent
square = partial(power, exponent=2)
print(square(5))
102532TypeError
Answer
B – 25
partial(power, exponent=2) creates a new function with exponent fixed to 2. Calling square(5) computes 5 ** 2 = 25.
Question 7
When multiple decorators are stacked, in what order are they applied?
@decorator_a
@decorator_b
def func():
pass
decorator_ais applied first, thendecorator_b.decorator_bis applied first, thendecorator_a.Both are applied simultaneously.
The order depends on the function’s arguments.
Answer
B – decorator_b is applied first, then decorator_a.
Stacked decorators are applied bottom to top. This is equivalent to func = decorator_a(decorator_b(func)). The innermost decorator (closest to the function) is applied first.
Question 8
What does callable(42) return?
TrueFalse42TypeError
Answer
B – False
Integers are not callable. Only objects that can be invoked with parentheses (functions, classes, objects with __call__) return True from callable().
Question 9
What is the output of the following code?
def make_greeter(greeting):
def greet(name):
return f"{greeting}, {name}!"
return greet
hi = make_greeter("Hi")
hello = make_greeter("Hello")
print(hi("Bob"))
"Hello, Bob!""Hi, Bob!""greeting, Bob!"NameError
Answer
B – "Hi, Bob!"
Each call to make_greeter creates an independent closure. hi captures "Hi" and hello captures "Hello". They do not interfere with each other.
Question 10
Which of the following correctly describes a higher-order function?
A function that uses recursion.
A function that takes another function as an argument or returns a function.
A function defined inside a class.
A function with more than three parameters.
Answer
B – A function that takes another function as an argument or returns a function.
Higher-order functions operate on other functions. Examples include map, filter, sorted (with key), and any decorator.
Question 11
What is the output of the following code?
nums = [1, 2, 3, 4, 5]
result = list(filter(lambda x: x % 2 == 0, nums))
print(result)
[1, 3, 5][2, 4][1, 2, 3, 4, 5][]
Answer
B – [2, 4]
filter keeps elements for which the lambda returns True. The lambda checks if a number is even (x % 2 == 0), so only 2 and 4 are kept.
Question 12
What is the output of the following code?
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(2)
def say_hi():
print("Hi")
say_hi()
Hi(printed once)Hi(printed twice)TypeErrorNothing is printed.
Answer
B – Hi (printed twice)
@repeat(2) creates a parameterized decorator. repeat(2) returns decorator, which wraps say_hi so that calling it executes the original function 2 times.
Question 13
Which of the following is a requirement for a closure?
The inner function must be defined with
lambda.The inner function must reference a variable from the enclosing function’s scope.
The enclosing function must use the
globalkeyword.The inner function must accept
*argsand**kwargs.
Answer
B – The inner function must reference a variable from the enclosing function’s scope.
A closure requires: a nested function, a reference to a free variable from the enclosing scope, and the enclosing function returning the nested function.
Question 14
What is the output of the following code?
def compute_square(x):
return x ** 2
f = compute_square
print(f(4))
print(type(f))
16then<class 'int'>16then<class 'function'>TypeErrorNonethen<class 'function'>
Answer
B – 16 then <class 'function'>
f = compute_square assigns the function object (not the return value) to f. Calling f(4) returns 16, and type(f) is <class 'function'>.
Question 15
What is the key difference between map and filter?
maptransforms each element;filterselects elements based on a condition.mapreturns a list;filterreturns a tuple.mapworks with strings only;filterworks with numbers only.mapmodifies the original list;filtercreates a copy.
Answer
A – map transforms each element; filter selects elements based on a condition.
map(func, iterable) applies func to every element and returns the transformed values. filter(func, iterable) returns only those elements for which func returns True. Both return lazy iterators.
True or False#
Question 16
True or False: In Python, functions are first-class objects and can be assigned to variables, passed as arguments, and returned from other functions.
Answer
True
Functions in Python are first-class objects. They can be assigned to variables, passed to other functions as arguments, returned from functions, and stored in data structures like lists and dictionaries.
Question 17
True or False: A lambda function can contain multiple statements separated by semicolons.
Answer
False
Lambda functions are restricted to a single expression. They cannot contain statements (assignments, loops, try/except, etc.). For multi-line logic, use a regular def function.
Question 18
True or False: A closure’s captured variables are destroyed when the enclosing function returns.
Answer
False
The captured variables survive through cell objects stored in the inner function’s __closure__ tuple. Even after the enclosing function returns and its local scope is discarded, the cell objects keep the captured values alive.
Question 19
True or False: functools.partial calls the original function immediately with the frozen arguments.
Answer
False
functools.partial does not call the function. It returns a new callable with some arguments pre-filled. The function is only called when you invoke the partial object with the remaining arguments.
Question 20
True or False: The nonlocal keyword is required to read a variable from an enclosing scope inside a nested function.
Answer
False
You can read variables from an enclosing scope without nonlocal. The nonlocal keyword is only required when you want to modify (reassign) a variable in the enclosing scope.
Question 21
True or False: Decorators can only be applied to functions, not to classes or methods.
Answer
False
Decorators can be applied to functions, methods, and classes. For example, @staticmethod, @classmethod, and @dataclass are all commonly used decorators applied to methods or classes.
Question 22
True or False: map and filter return lists in Python 3.
Answer
False
In Python 3, map and filter return lazy iterators, not lists. You must wrap the result in list() to materialize all values.
Question 23
True or False: PEP 8 discourages assigning a lambda to a variable name.
Answer
True
PEP 8 states that assigning a lambda to a variable (e.g., f = lambda x: x + 1) defeats the purpose of lambdas. If you need a named function, use def instead. Lambdas are intended for short, inline use.
Question 24
True or False: Two closures created by the same enclosing function share the same captured state.
Answer
False
Each call to the enclosing function creates a new, independent closure with its own set of captured variables. Two closures from the same factory do not share state.
Question 25
True or False: A parameterized decorator (decorator with arguments) requires three levels of nested functions.
Answer
True
A parameterized decorator uses three layers: the decorator factory (takes the arguments), the decorator (takes the function), and the wrapper (replaces the function). The pattern is factory(args) -> decorator(func) -> wrapper(*args, **kwargs).
Essay Questions#
Question 26
Explain what a closure is and the three conditions required for one to exist. Provide a brief example.
(2-4 sentences)
Answer Guidelines
Key points to include:
A closure is a function that retains access to variables from its enclosing scope even after the enclosing function has returned.
Three conditions: (1) a nested function exists, (2) the nested function references a free variable from the enclosing scope, and (3) the enclosing function returns the nested function.
Python uses cell objects to keep the captured variables alive after the enclosing scope is discarded.
Example: a
make_counterfunction that returns anincrementfunction which remembers and updates acountvariable.
Question 27
Explain why ``functools.wraps`` is important when writing decorators. What happens if you omit it?
(2-4 sentences)
Answer Guidelines
Key points to include:
When a decorator wraps a function, the wrapper function replaces the original. Without
@wraps, the original function’s__name__,__doc__,__module__, and other metadata are lost.functools.wrapscopies these attributes from the original function onto the wrapper.This is important for debugging (stack traces show the correct name), documentation generators, and any tool that inspects function metadata.
Best practice: always use
@functools.wraps(func)in every decorator wrapper.
Question 28
Compare ``functools.partial``, lambda expressions, and closures as ways to pre-fill function arguments. When would you prefer each approach?
(2-4 sentences)
Answer Guidelines
Key points to include:
functools.partialis best for simple argument freezing; it preserves introspection via.func,.args, and.keywordsattributes.Lambda expressions are good for short, inline transformations where the logic fits in a single expression.
Closures offer the most flexibility: they can contain complex logic, maintain mutable state, and perform additional processing beyond simple argument binding.
Rule of thumb: use
partialfor straightforward cases, lambda for one-liners, and closures when you need state or multi-step logic.
Question 29
Explain how stacked decorators are applied. Given @A on top of @B on top of a function f, describe the order of execution.
(2-4 sentences)
Answer Guidelines
Key points to include:
Stacked decorators are applied bottom to top:
@Bis applied first, then@A.The equivalent expression is
f = A(B(f)).At call time, the outermost wrapper (from
A) executes first, then the wrapper fromB, then the original functionf.This means the decorator closest to the function definition is applied first during decoration, but its wrapper is called last during execution.
Question 30
Describe the difference between a pure function and an impure function. Why do functional programming advocates prefer pure functions?
(2-4 sentences)
Answer Guidelines
Key points to include:
A pure function depends only on its inputs and produces no side effects (no modifying external state, no I/O). Given the same inputs, it always returns the same output.
An impure function may modify global variables, mutate arguments, perform I/O, or depend on external state, making its behavior harder to predict.
Pure functions are preferred because they are easier to test, debug, and reason about. They also enable safe parallelism since they do not share mutable state.
In practice, most programs need some impure functions (for I/O, logging, etc.), but minimizing side effects improves code quality.