Python Supports Closures
Closures are referred to as “functions that refer to variables from the scope in which they were defined.”
Example
def sort_priority(values, group):
def helper(x):
if x in group:
return (0, x)
return (1, x)
values.sort(key=helper)
In this example, helper
method has access to the variable group
due to the closures.
Example with a Variable Assignment
However, in another example, we can observe closures do not work for variable assignment:
def sort_priority2(numbers, group):
found = False
def helper(x):
if x in group:
found = True
return (0, x)
return (1, x)
numbers.sort(key=helper)
return found
This time, found
variable remains as False
value and it’s because closure works differently for a variable assignment.
If the variable is already defined in the current scope, it will just take on the new value. If the variable doesn’t exist in the current scope, Python treats the assignment as a variable definition.
For this reason, found = True
within helper
method is a new variable assignment, instead of re-assignment of value for found
in sort_priority2
method.
Remedy
Using nonlocal
Statement
The
nonlocal
statement is used to “indicate that scope traversal should happen upon assignment for a specific variable name”. The only limit is thatnonlocal
won’t traverse up to the module-level scope (to avoid polluting globals).
The author of the book cautions against using nonlocal
for anything more than simple due to its side effects.
Instead, he recommends using a helper class.
Using a Helper Class
Writing a helper class may be a bit longer than using nonlocal
, but it can be much easier to read.
class Sorter:
def __init__(self, group):
self.group = group
self.found = False
def __call__(self, x):
if x in self.group:
self.found = True
return (0, x)
return (1, x)
sorter = Sorter(group)
numbers.sort(key=sorter)
assert sorter.found is True
Order of Python Interpreter Treversing Scope:
- The current function’s scope
- Any enclosing scopes (such as other containing functions)
- The scope of the module that contains the code (also called the global scope)
- The built-in scope (that contains functions like
len
andstr
)
References
- Effective Python: Know How Closures Interact with Variable Scope