Scope

Python has three scopes: local, closure/nonlocal/outer, global. This section will discuss things below: Is variables a local, nonlocal or global?

  • If no nonlocal and global used, variables defined inside function are local variables.

  • When there is a function defined inside another function, in inner funcitoin, nonlocal varialbes are variables defined in outer function.

  • global variables are variables outside of functions, aka in module level

Rule

  • You could use a closure variable by using nonlocal and you could use a global variable by global. If nonlocal or global are used, then both lookup and store refer to nonlocal or global. e.g.:

  nonlocal var
  var    =   var + 1
   ↑          ↑
nonlocal   nonlocal

In this case, two var in both sides of “=” are nonlocal var.

  • If there isn’t nonlocal or global used, the way python search variable is in order local, closure/nonlocal/outer, global.

Using local

var = "global"
def outer():
    var = "nonlocal"
    def inner():
        var = "local"
        print(var)
    return inner

>>> outer()()
local

Using nonlocal

var = "global"
def outer():
    var = "nonlocal"
    def inner():
        # var = "local"
        print(var)
    return inner

>>> outer()()
nonlocal

Using global

var = "global"
def outer():
    # var = "nonlocal"
    def inner():
        # var = "local"
        print(var)
    return inner

>>> outer()()
global

How to assgin var to another var which has different scope

I want to have a local var in inner instead of using nonlocal var. Question: How to assign a nonlocal var to local var.

Solution 1: Just have some variable name with init “l”, short of local:

def outer():
    var = 1
    def inner(var=var):
         var += 1
         return var
    return inner

Solution 2: Assignment will automatically create local variables in default argument assignment.

def outer():
    var = 1
    def inner():
         nonlocal var
         lvar = var + 1
         return lvar
    return inner

What tool could be used to check scope

The type of three scopes could be check by python -mdis xxx.py

The meaning in disassembly:

Scope

local

nonlocal

global

Disassembly READ

LOAD_FAST

LOAD_DEREF

LOAD_GLOBAL

Disassembly STORE

STORE_FAST

STORE_DEREF

STORE_GLOBAL

If you find LOAD_DEREF in inner function which means using nonlocal variable. You may also find LOAD_CLOSURE in def inner(…) line.

You could check closure by:

out = outer()
out.__closure__[0].cell_contents