Python · Advanced 3
Closures, Decorators and Context Managers
Name
Class
Date
Mark / 31
Section A
Circle the letter of the correct answer. One mark each.
- 1What is a closure?1
- AA function that closes a file
- BA function that remembers variables from the scope it was defined in
- CA function that has no return value
- DA function with no parameters
- 2What does
nonlocal countdo inside an inner function?1- APrevents count being used
- BMakes count a global variable
- CMakes assignments to count change the enclosing function's variable
- DDeletes count
- 3A function make_counter() returns a closure with its own count. If you call it twice, what do the two closures share?1
- AThe same count
- BNothing: each has its own count
- COnly the function name
- DThe return value
- 4What does
@my_decoratorabovedef f():mean?1- Amy_decorator = f(my_decorator)
- Bf is deleted
- Cf runs my_decorator once
- Df = my_decorator(f)
- 5Why is
functools.wrapsused in a decorator?1- ATo keep the original function's name and docstring on the wrapper
- BTo make the function run faster
- CTo make the function private
- DTo catch exceptions
- 6What does
*args, **kwargsallow a wrapper function to do?1- AAccept and pass on any arguments
- BAccept only keyword arguments
- CSkip the original function
- DReturn several values
- 7What is the extra layer needed for a decorator such as @repeat(3)?1
- AA global variable to hold the 3
- BA second @ line
- CA function that takes the argument and returns the actual decorator
- DA class to wrap the function
- 8When does the __exit__ method of a context manager run?1
- AOnly if no exception occurred
- BWhen the program ends
- CAt the end of the with block, even if an exception occurred
- DAt the start of the block
- 9In a database transaction used in a with block, what happens if an exception is raised inside the block?1
- AThe changes are rolled back
- BThe changes are committed
- CThe changes are kept but not saved
- DThe database is deleted
- 10What is a callback?1
- AAn error handler for files
- BA function that returns its arguments
- CA function that calls itself
- DA function passed to other code, to be called later
Section B
Answer in the space provided. The number of marks tells you how many separate points to make.
- 1ExplainExplain what is meant by a closure in Python.3
- 2StateThe program shown is run. State the output and explain why the second and third values printed are different.4Python
def make_counter(): count = 0 def counter(): nonlocal count count += 1 return count return counter a = make_counter() b = make_counter() print(a(), a(), b()) - 3WriteWrite a decorator called log_calls that prints the name of the function it decorates each time that function is called, and then calls the function and returns its result. The decorated function may have any parameters.5
- 4ExplainExplain why using a with statement to open a file is better than calling open and close separately.3
- 5DiscussDiscuss the advantages and disadvantages of using decorators in a large program.6
Mark scheme
Section A
Section B
1 Explain what is meant by a closure in Python. 3
One mark for each of the following, to a maximum of 3.
- A closure is a function defined inside another function
- It uses variables from the enclosing function
- It keeps (remembers) those variables even after the outer function has finished
Model answer. A closure is a function that is defined inside another function and uses variables from the enclosing function. It keeps, or remembers, those variables even after the outer function has finished running, so the inner function can carry on using them when it is called later.
2 The program shown is run. State the output and explain why the second and third values printed are different. 4
One mark for each of the following, to a maximum of 4.
- The output is 1 2 1
- Each call of make_counter creates a new function with its own variable count
- a() adds 1 to the count that belongs to a, so the second call gives 2
- b has its own count, which starts again at 0, so its first call gives 1
Model answer. The output is 1 2 1. Each call of make_counter creates a new inner function with its own variable count. The first two calls to a each add 1 to the count that belongs to a, giving 1 and then 2. The function b has its own separate count, which starts at 0, so its first call gives 1.
3 Write a decorator called log_calls that prints the name of the function it decorates each time that function is called, and then calls the function and returns its result. The decorated function may have any parameters. 5
One mark for each of the following, to a maximum of 5.
- A function that takes a function as a parameter
- Defines a wrapper function inside it which accepts any arguments (*args, **kwargs)
- The wrapper prints the name of the function
- The wrapper calls the original function with the arguments and returns its result
- The decorator returns the wrapper
Model answer.
def log_calls(func):
def wrapper(*args, **kwargs):
print("calling", func.__name__)
return func(*args, **kwargs)
return wrapper
@log_calls
def add(a, b):
return a + b
print(add(2, 3))log_calls takes the function as a parameter and defines a wrapper inside it. The wrapper accepts any arguments, prints the function's name, calls the original function with those arguments and returns what it returns. log_calls then returns the wrapper, which replaces the original function when the @ syntax is used.
4 Explain why using a with statement to open a file is better than calling open and close separately. 3
One mark for each of the following, to a maximum of 3.
- The file is closed automatically at the end of the with block
- This happens even if an error (exception) occurs inside the block
- With separate open and close, the close call could be skipped, leaving the file open and data possibly not saved
Model answer. With a with statement the file is closed automatically as soon as the block ends, and this happens even if an error occurs inside the block. If open and close are called separately, an error between them can mean the close call is never reached, or the programmer may forget it, leaving the file open so that data may not be saved and the file may stay locked.
5 Discuss the advantages and disadvantages of using decorators in a large program. 6
One mark for each of the following, to a maximum of 6.
- A decorator lets the same extra behaviour, such as logging, timing or checking, be added to many functions without repeating the code
- The original function stays simple and focused on its own job (separation of concerns)
- The behaviour can be added or removed by adding or removing one line
- Disadvantage: the behaviour is hidden above the function so a reader may not realise it is there, and it can be harder to follow
- Disadvantage: the extra layer of function calls can make debugging more difficult and slightly slower, and a poorly written one can lose the function's name
- A reasoned conclusion: worthwhile for behaviour shared across many functions, but should be kept small and documented
Model answer. A decorator lets the same extra behaviour, such as logging, timing, checking arguments or caching, be added to many functions without repeating the code in each, so the program is shorter and the code is easier to maintain. Each original function stays simple and concentrates on its own job, and the extra behaviour can be added or removed by adding or removing a single line. There are disadvantages. The behaviour is hidden above the function, so a reader may not realise it is there, which can make the code harder to follow. The extra layer of function calls can also make debugging more difficult and slightly slower, and a badly written decorator can lose the original function's name and documentation. Decorators are therefore worthwhile for behaviour shared by many functions, provided each is kept small and documented.