Scope
LEGB Rules
Python search variable name by a hierarchy levels
  • Local can be inside a function or class method
  • Enclosed can be its enclosing function
  • Global refers to the uppermost level of the executing script itself
  • Built-in are special names that Python reserves for itself
  • One sentence rule: the reference of a variable is visible to all its lower levels, thus mutable variables are visible and able to be modified in the lower levels, immutable variables are visible in the lower levels, but not able to be modified since the modification will create a local variable instead of modify the variable in the upper levels

  • dir() will give you the list of in scope variables
  • globals() will give you a dictionary of global variables
  • locals() will give you a dictionary of local variables
    1. n = 10; #global variables
    2.  
    3. def f():
    4. m = 100;
    5. print(dir()) # ['m']
    6. print(globals()) # {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x108df2860>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 's1.py', '__cached__': None, 'n': 10, 'f': <function f at 0x108cf52f0>}
    7. print(locals()) # {'m': 100}
    8.  
    9. print(dir()) # ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'f', 'n']
    10. f();
    1. n = 10 # global variable
    2. print(id(n), n) # 4405450128 10
    3. # access local variable
    4. def f1():
    5. n = 1;
    6. print(id(n), n) # 4450449840 1, reference local variable n
    7. # access variable in enclosing function
    8. def f2():
    9. n = 2;
    10. def f3():
    11. print(id(n), n) # 4405449872 2, reference n defined in f2
    12. f3();
    13. # access global variable
    14. def f4():
    15. def f5():
    16. print(id(n), n) # 4405450128 10, reference global variable
    17. f5();
    18. f1();
    19. f2();
    20. f4();
    Immutable
    1. a = 10 # global variable
    2. print(id(a), a) # 27193472, 10
    3. def f1():
    4. # global variable is visible to the lower level
    5. # globals: {'a': 10, ...}
    6. print(id(a), a) # 27193472, 10
    7. def f2():
    8. # create a local variable, which screens the global variable
    9. # globals: {'a': 10, ...}
    10. a = 100
    11. # locals: {'a': 100}
    12. print(id(a), a) # 27195296 100
    13. f1()
    14. f2()
    15. print(id(a), a) # 27193472, 10
    Mutable
    1. l = list(range(10)) # global variable
    2. print(id(l), l) # 140678046472600, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    3. def f3():
    4. # the reference of the gocal variable is visible to the lower level
    5. print(id(l), l) # 140678046472600, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    6. def f4():
    7. # modify an element of the global variable
    8. l[1] = 100
    9. print(id(l), l) # 140678046472600, [0, 100, 2, 3, 4, 5, 6, 7, 8, 9]
    10. f3()
    11. f4()
    12. print(id(l), l) # 140678046472600, [0, 100, 2, 3, 4, 5, 6, 7, 8, 9]
    13. def f5():
    14. # create a local variable, which screens the global variable
    15. l = [1, 2, 3, 4]
    16. print(id(l), l) # 139718240373432, [1, 2, 3, 4]
    17. f5()
    18. print(id(l), l) # 140678046472600, [0, 100, 2, 3, 4, 5, 6, 7, 8, 9]
    global keyword
    1. t = 10
    2. print(id(t), t) # 140417416870688, 10
    3. def f8():
    4. global t # t is a global variable
    5. print(id(t), t) #140417416870688, 10
    6. t = 100 # modify the global variable t, create a new address, reference global variable to new address
    7. print(id(t), t) #140249594380832, 100
    8. print('globals: ', globals()) # globals: {'t': 100}
    9. print('locals: ', locals()) # locals: {}
    10. f8()
    11. print(id(t), t) # 140249594380832, 100
    import module
    1. def f():
    2. import math; # import math in local namespace
    3. print(math.pi)
    4. f();
    5. #print(math.pi) # not import math error
    global variable among modules

  • global_list is imported once
  • global_list is shared by both module a and module b
    1. # g.py
    2. global_list = [1, 2]
    3. print('g', id(global_list), global_list)
    1. # a.py
    2. print('a ...')
    3.  
    4. #import g
    5. from g import global_list
    6.  
    7. def change():
    8. global_list.append(100)
    9.  
    10. change()
    11. print('a', id(global_list), global_list)
    1. # b.py
    2. print('b ...')
    3.  
    4. #import g
    5. from g import global_list
    6. from a import *
    7.  
    8. def display():
    9. print('display', id(global_list), global_list)
    10.  
    11. print('b', id(global_list), global_list)
    12.  
    13. change()
    14. display()
    1. # python b.py
    2. b ... # start module b
    3. g 140597500568384 [1, 2] # import module g
    4. a ... # import module a
    5. a 140597500568384 [1, 2, 100] # global_list in a
    6. b 140597500568384 [1, 2, 100, 100] # global_list in b

  • global_list is imported once, no need to import in b again
    1. # g.py
    2. global_list = [1, 2]
    1. # a.py
    2. print('a ...')
    3.  
    4. from g import global_list
    5.  
    6. print('a', id(global_list), global_list)
    1. # b.py
    2. print('b ...')
    3.  
    4. from a import *
    5.  
    6. print('b', id(global_list), global_list) # global_list is available in b.py
    Resource
  • Visibility of global variables in imported modules
  • Beginner's Guide
  • Namespace at Python Course