PCAP Closures and Decorators 1 — Questions and Answers
Question 1: What is a closure in Python?
- An inner function that captures and remembers variables from the enclosing scope even after the outer function has returned (Correct answer)
- A function that returns multiple values using a tuple
- A class that implements the __call__ method to behave like a function
- A function that blocks access to global variables
Correct answer: An inner function that captures and remembers variables from the enclosing scope even after the outer function has returned
A closure is a nested function that retains access to variables from its enclosing scope, allowing those variables to persist beyond the outer function's lifetime.
Question 2: What will the following code print? def outer(x): def inner(y): return x + y return inner add5 = outer(5) print(add5(3))
- 8 (Correct answer)
- 5
- 3
- TypeError: unsupported operand type
Correct answer: 8
`outer(5)` returns `inner` with `x` closed over as 5, so calling `add5(3)` computes 5 + 3 = 8.
Question 3: What is the `nonlocal` keyword used for inside a nested function?
- To modify a variable defined in the nearest enclosing non-global scope (Correct answer)
- To declare a constant that cannot be reassigned
- To import names from an enclosing module's namespace
- To access global variables without writing the global keyword
Correct answer: To modify a variable defined in the nearest enclosing non-global scope
`nonlocal` tells Python that an assignment in the nested function targets the variable in the enclosing scope rather than creating a new local variable.
Question 4: Which attribute of a function object holds the variables captured by its closure?
- __closure__ (Correct answer)
- __globals__
- __dict__
- __captured__
Correct answer: __closure__
`func.__closure__` is a tuple of cell objects, each holding the value of one variable captured from the enclosing scope.
Question 5: What will this code output? def make_counter(): count = 0 def counter(): nonlocal count count += 1 return count return counter c = make_counter() print(c(), c(), c())
- 1 2 3 (Correct answer)
- 0 1 2
- 1 1 1
- NameError: name 'count' is not defined
Correct answer: 1 2 3
Each call to `c()` increments the shared `count` variable via `nonlocal`, producing 1, 2, then 3.
Question 6: What will the following code print? def outer(): x = 10 def inner(): print(x) x = 20 return inner f = outer() f()
- 20 (Correct answer)
- 10
- NameError: name 'x' is not defined
- None
Correct answer: 20
Closures capture the variable binding (a reference to the cell), not a snapshot of the value at definition time, so `x` is 20 when `inner` runs.
Question 7: Which of the following is the most common practical use case for closures in Python?
- Factory functions that return specialized functions with pre-configured parameters (Correct answer)
- Replacing class-based inheritance hierarchies entirely
- Speeding up loops by caching loop indices
- Catching exceptions without using try/except blocks
Correct answer: Factory functions that return specialized functions with pre-configured parameters
Closures are frequently used as factory functions (e.g., `make_adder(n)` returns a function that adds `n`) to produce families of related functions that carry private state.
What is a closure in Python?