When you use a name in a Python program such as variable name function name,etc, Python creates, changes or looks up the name in a namespace. A namespace is the complete list of names that exists in a given context.
There are two types of namespaces, global namespace and local namespace.
The scope of an object determines the locations in the program where it can be accessed, by default, objects are only accessible from within the namespace that they occur. Objects in the global namespace are accessible from anywhere in the program, this are the names that are declared at the top level of a module or a script i.e not inside a function, a class, etc. On the other hand, names declared inside a block such as a function are local to that block and are only accessible within the block.
When we define a function, Python sets up a local namespace for the function. Any object declared inside the function will only be accessible within the function, the object is said to be local to that function. Trying to access local objects outside their scope will raise a NameError
. For example:
def demo():
x = 100
print(x)
demo()
//100
print(x)
//NameError: name 'x' is not defined
Objects inside a function are localized such that they will not crash with objects with similar names outside that function.This allows same name to be used for different objects in different scopes without causing conflicts.
If a function declares a name that also exists in the global namespace, the local name takes precedence over the global name and overwrites it only inside that function. Example:
x = 200
def demo():
x = 100
print(x)
demo()
//100
print(x)
//200
In the above example, there are two distinct variables with a name x
, one in the global namespace with a value of 200
and another in function demo's local namespace with a value of 100
. The value of x
is, therefore, determined by the location where we are using it. Making any changes to the'x'
inside the function demo does not affect in any way the value of the 'x'
outside its scope.
Name Resolution, The LEGB Rule
When we mention an object by name, the Python interpreter follows an inside-out approach in order to identify the object we are referring to. This approach is often referred to as the LEGB rule, which stands for Local, Enclosing, Global, Built-in. This rule can be summarized as follows:
- Local, first : Look for this name first in the local namespace and use local version if available. If not, go to higher namespace.
- Enclosing, second : If the current function is enclosed within another function, look for the name in that outer function. If not, go to higher namespace.
- Global, third : Look for the name in the objects defined at global namespace
- Built-in,last : Finally, look for the variable among Pythonโs built-in names.
If the interpreter goes through all the 4 stages and does not locate the name, a NameError
is raised, of course if the operation was not an assignment operation in which case an object with that name will be created in the local scope instead of raising the error.
Example:
x = 200
def demo():
x = 300
def inner():
print(x)
inner()
demo()
//300
In the above case, in the call to printx
, the interpreter fails to find an object with a name x
in the function inner
's scope, it moves outward to the enclosing function in which case it finds an'x'
with a value of 300
thus terminating the search. If still an object with a name 'x'
was not located in the enclosing function 'demo'
, the globalx
with a value of 200
would have been returned.
More Examples:
x = 500
def demo():
print(x)
x = 300
print(x)
demo()
//500
//300
def demo2():
y = 400
def inner():
print(x + y)
inner()
demo2()
//900
The Global Statement
The global
statement is the only thing that is capable of transforming a name defined inside a function to a global name. This means that the name will behave just like names defined in the global namespace and will be accessible from anywhere in the program.
Examples:
def demo():
global x
x = 200
demo()
print(x)
//200
If a global name exists similar to the name specified in the global statement, any modifications done to the object it identifies will take effect at a global level. Examples:
x = 100
def demo():
global x
x = 500
demo()
print(x)
//500
To declare multiple global names in one global statement, we use the global keyword followed by the comma separated names, example:
def demo():
global x, y, z
x = 4
y = 3
z = x + y
demo()
print(x, y, z)
//4, 3, 7
While the global statement can be useful at times, it can make code mor obscured as it can make it difficult to keep track of the global names. It should, therefore, be avoided whenever possible, after all names inside a function are made local to that function by default because it is the best policy. We can Instead, pass global values as function arguments and then return the modified values.
The nonlocal Statement
The nonlocal
statement is a close cousin of the global
statement. While the global
statement makes a name available at global level, the nonlocal
statement makes a name available to the enclosing function's scope. This also allows the nested function to make changes to variables defined in the enclosing function. Examples:
def demo():
x = 400
def inner():
nonlocal x
x = 600
inner()
print(x)
demo()
//600
def demo2():
def inner():
nonlocal y
y = 500
inner()
print(y)
demo2()
//500
Note: We cannot use the nonlocal
statement with a top level function, trying this will raise a SyntaxError
def demo():
nonlocal y
y = 100
demo()
//SyntaxError: no binding for nonlocal 'y' found
Top comments (0)