EP 15 Know How Closures Interact with Variable Scope

  • 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]

  1. The current function's scope
  2. Any enclosing scope (like other containing functions)
  3. The scope of the module that contains the code(also called the global scope)
  4. The built-in scope(that contains functions like len and str)

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)

Recommended Posts

EP 15 Know How Closures Interact with Variable Scope
Effective Python Note Item 15 Know how closures relate to function scope
Variable scope