- Closure functions can refer to variables from any of the scopes in wihch they were defined.
Effective Python
Scope
Say you want to sort a list of numbers but prioritize one group of numbers to come first.
def sort_priority(values, group):
def helper(x):
if x in group:
return (0, x)
return (1, x)
values.sort(key=helper)
In [2]: numbers = [8, 3, 1, 2, 4, 5, 7,6]
In [3]: group = {2, 3, 5, 7}
In [4]: sort_priority(numbers, group)
In [5]: print(numbers)
[2, 3, 5, 7, 1, 4, 6, 8]
Cause Scope Bug
def sort_priority2(numbers, group):
found = False # Scope: sort_priority2
def helper(x):
if x in group:
found = True # Scope: helper -- Bad
return 0, x
return 1, x
numbers.sort(key=helper)
return found
>>> l = [4, 6,2,5,7,9, 0]
>>> found = sort_priority2(l, [2,5,8])
>>> found
False
>>> l
[2, 5, 0, 4, 6, 7, 9]
Getting Data out
nonlocal
Python 3
def sort_priority2(numbers, group):
found = False # Scope: sort_priority2
def helper(x):
nonlocal found
if x in group:
found = True # Scope: helper -- Bad
return 0, x
return 1, x
numbers.sort(key=helper)
return found
The nonlocal statement is used to indicate that scope traversal should happen upon assiginment for a specific variable name. The only limit is that nonlocal won't traverse up to the module-level scope (to avoid polluting globals)