Need several functions that add different fixed amounts? Define a function inside another function. The outer function can return that inner function, letting each call create a callable with its own chosen amount. section 7.2.3
Make incrementing functions
def increment_maker(number): def increment(value): return value + number return increment increment_one = increment_maker(1) increment_three = increment_maker(3) print(increment_one(99), increment_three(88)) # output: 100 91 The inner function uses number from the outer function and receives value when called. Return increment itself, not the result of calling it. section 7.2.3
An inner function has its own local scope. When a returned inner function uses a variable from its enclosing function, it forms a closure. That pattern also underlies decorators: a decorator accepts a function and returns an inner function that wraps it. section 7.3.2 section 10.4.3
Listing 10.9 Changing a nonlocal variable
def change_text(using_nonlocal: bool):
text = "N/A"
def inner_fun0():
text = "No nonlocal"
def inner_fun1():
nonlocal text
text = "Using nonlocal"
inner_fun1() if using_nonlocal else inner_fun0()
return text
change_text(using_nonlocal=False)
# output: 'N/A'
change_text(using_nonlocal=True)
# output: 'Using nonlocal'
Compare the two assignments to text. Without nonlocal, assignment creates a name in the inner function’s local scope and the outer value stays 'N/A'. With nonlocal, it changes the enclosing value to 'Using nonlocal'. section 10.4.3
For a decorator wrapper, plan for the wrapped function’s arguments and return value. A wrapper that accepts no arguments fails when the decorated function is called with one; a wrapper that omits return loses the decorated function’s result. Decoration can also replace the apparent function name and docstring with the inner function’s metadata; apply functools.wraps to the wrapper to preserve them. section 7.3.2 section 7.3.3




