Prev: Arguments | Next: Functions as first-class objects
def addcon(x,y):
asum = x+y
return asum
a = 5
b = 10
c = addcon(a,b)
print(c)
- global: by global we refer to the namespace of the main program. This contains the names 'addcon', 'a', 'b' and their object bindings. A variable 'is global' ('has global scope') when it belongs to the global namespace and, therefore, it can certainly be used in the main program (and elsewhere as explained further below)
- local: by local we refer to the namespace created by a function while it is executed. In our example the addcon local namespace includes the names 'x', 'y', 'asum' and their object bindings. A variable 'is local' ('has local scope') when it belongs to a function local namespace and, therefore, it can certainly be used in that function
1) Variables belong where the binding is first constructed: if it is constructed in the main program the variable is global. If in a function then the variable is local in that function. 'Constructed' in this context means that a name-object binding was established by an assignment command, such as: x=5, y='spam', alist=[], adict={}, etc.
def addcon(x,y):
asum = x+y # asum is a local var 'constructed' in the function by this assignment
return asum
a = 5 # a and b are global vars 'constructed' in the global namespace of the main program
b = 10
c = addcon(a,b) # c is also a global var 'constructed' by this assignment
print(c)
2) If a variable is used somewhere but NOT constructed there: then Python interpreter looks up for this variable at the higher levels of a scope hierarchy. If the variable is identified at some level then it is assigned the scope of that level and computation continuous. If it is not identified at any level then a 'NameError' exception is raised and execution is terminated.
3) Scope hierarchy: Python looks for variable scope following the 'LEGB' hierarchy, which means:
- Local: a variable is sought for first in the local namespace (in the function) where it is used
- Enclosing: the next level is any enclosing (container) function containing the function where the variable is used
- Global: the upper level is the global level of the main program
- Built-ins: finally Python searches for a variable in the built in names that the language reserves (for example, len, sum, class, etc.)
When an module is imported then the namespace is further extended and prefixes are commonly used to correctly identify the imported namespaces.
def func1():
def func2():
x = 300 # x is local in func2() because of this assignment
return x
x = 200 # another x is local in func1() because of this assignment
a = func2()
b = x
return a, b
x = 100 # another x is global; is different from x's in func1() and func2()
print(func1())
print(x)
def func1():
def func2():
x = 300+a # a is NOT local in func2() but identified in the higher 'Enclosing' level
return x
x = 100+y # y is NOT local in func1() but identified in the higher 'Global' level
a = 400
b = func2()
return a, b
x = 100
y = 300
print(func1())
print(x)
def func1():
def func2():
x = 300+a
c = 700 # c is local here and NOT available in higher levels of the hierarchy
return x
x = 200+y
a = c #--- this returns: 'NameError: name 'c' is not defined'
b = x
return a, b
x = 100
y = 500
print(func1())
print(x)
print(c) #--- this returns: 'NameError: name 'c' is not defined'
4) global and nonlocal: There are two 'declarations' that help override the above rules when necessary:
- global: when declaring a var as global in a function, it's scope becomes automatically 'global'
- nonlocal: when declaring a var as nonlocal in an enclosed function, it's scope becomes automatically local in the function above (the enclosing function)
See the examples:
def func1():
def func2():
nonlocal x # x is declared as nonlocal; thus, it is identical to 'x' in the higher enclosing func1()
x = 300
return x
x = 200 # because of 'nonlocal' now this 'x' is identical to the 'x' var in enclosed func2()
a = func2()
b = x # Now b gets the value '300'. Why?
return a, b
x = 100 # this x is global and different from x in func1()
print(func1())
print(x)
def func1():
global x # x is declared as nonlocal; thus, it is identical to the global 'x' in main program
def func2():
x = 300
return x
x = 200
a = func2()
b = x # Now b gets the value '200'. Why?
return a, b
x = 100 # because of 'global' now this 'x' is identical to the 'x' var in func1()
print(func1())
print(x) # Now x gets the value '200'. Why?
5) Mutable vs. immutable object behavior: when thinking about scope always recall the different behavior of mutable/immutable objects when assigned values in a function:
- Immutable objects (integerss, strings,..): any assignment is considered as construction and the variable becomes local (a new copy is created). Any global variable of the same name stays intact.
- Mutable objects (lists, dictionaries,..): assignment of a new value to a member is not considered construction. Any global variable of the same name is affected due to shared object reference.
def myfunc():
a = 31 # a is immutable; assignment constructs a new local obect in myfunc()
b[0] = 'K' # b is mutable; changing a member value does NOT construct new copy
return
a = 10
b = [1,2,3]
myfunc()
print(a, b) # global a is not affected by myfunc(); list b is affected because of shared object reference
. Free learning material
. See full copyright and disclaimer notice