Introduction
Understanding the namespaces, scopes, and behavior of variables in Python functions is crucial for writing efficiently and avoiding runtime errors or exceptions. In this article, we’ll delve into various aspects of namespaces and Python variable scopes and learn how Python manages local, global, and enclosing variables in detail.
We already discussed Python functions in detail, which can be found here. Python uses abstraction principles to hide complex logic and expose only the necessary outputs, while decomposition creates modular, readable, and reusable functions.
These principles are obvious enough to understand how Python handles its variable scopes for a function definition and nested functions, which we will explore through detailed examples. By the end of this article, you should clearly understand these concepts and how to apply them effectively in your programs.
Overview
- Python’s namespaces and variable scopes are crucial for efficient coding and error prevention.
- The article explores local, global, and enclosing variables’ behavior in Python.
- LEGB rule describes Python’s variable name search across different scopes.
- Practical examples demonstrate global and local variable use and modification.
- Nested functions and enclosing scope are covered, emphasizing the nonlocal keyword.
What are the Variables in Python?
Variables in Python are containers that store data or values (such as int, float, str, bool, etc.). The memory location where a variable is stored and also accessible for future use is called the scope of a variable.
There are two types of variables in Python, namely:
Global Variables
- These variables come under the scope of the main program.
- The main program cannot use the local variable, as it is only available for the function.
Local Variables
- These variables come under the scope of function.
- Also, the local variable can use the global variable inside the function when the local variable is not defined inside the local scope.
Also read: Mutable vs Immutable Objects in Python
What are the Namespaces?
Python namespace is a space or dictionary that holds identifiers (commonly called variable names) as its keys and their respective objects as the values in the memory space. Python programming language has 4 types of Namespaces, namely:
- Built-in Namespace
- Global Namespace
- Enclosing Namespace
- Local Namespace
We’ll soon look at different examples to better understand this concept. But before that, it is really important to understand the variable scopes mentioned above.
What are the Variable Scopes in Python?
In Python, scope refers to a program’s area or textual region where the variables are directly accessible. At any time during execution, there are :
- Local Scope: This is the innermost scope defined inside a function. For this scope, Python looks for the local variable.
- Enclosing Scope: These are the scopes of the nested functions. They contain non-local variables that are neither local nor global.
- Global Scope: This scope contains the variables defined at the module level and is accessible throughout the module.
Note: You create these user-defined scopes in your program to run it efficiently. However, Python’s Built-in Variables also have a scope known as Built-in Scope.
- Built-in scope: This is the scope of all the pre-defined keywords or methods Python offers for writing better codes. Hence, these are available to you as soon as the Python interpreter starts. Also, note that these scopes are never deleted and are accessible throughout the module.
What is the LEGB Rule?
Now, you have a basic understanding of namespaces and variable scope. Let’s dive deeper to understand how scoping rules are applied in Python Programming Language. There’s a common abbreviation, LEGB Rule, which stands for Local, Enclosing, Global, and Built-in.
LEGB Rule states that the interpreter can search for an identifier from the inside out, meaning it starts by looking for a variable name or namespace in the local scope first. If the namespace is not present there, it will move towards the enclosing scope of your program. ext, it checks the global scope to find the namespace. Finally, if the identifier is still not found, the interpreter looks at the built-in scope provided by Python.
Furthermore, if the interpreter doesn’t find the name in any of these locations, then Python raises a `NameError` exception, meaning the variable is not defined in the program.
Also, it is really important to remember that you’ll have to move upward in the hierarchy of the LEGB Rule from the current scope.
Also read: Comprehensive Guide to Advanced Python Programming
How does Python Variable Scope Work?
Now, let’s go one-by-one through all these examples to understand all these concepts in depth:
1. Using Global Variable in the Local Scope
To understand this let’s take an example, here the function `g(y)` not only prints the global variable `x` but also modifies it as `x+1`.
Now, since `x` is not defined within `g(y)`, Python fetches the value of global variable `x`.
def g(y):
print(x)
print(x+1)
# Since x is not in local scope it will go and fetch the value of x from global variable
x = 1
g(x) # Global Inside Local Variable
print(x) # Global Variable
Output
12
1
The output shows the value of `x` and `x+1` confirming that the global variable `x` remains unchanged, but has been used by the local scope for it to output the results properly.
2. Using Local Variable in the Local Scope
Now, look at this example, here we have a function definition `g(y)` and inside below given function `g`, name `x` is defined as a local variable and also modified.
def g(y):
x = 10 # Local variable
x += 1
print(x)
x = 1 # Global Variable
g(x)
print(x)
Output
111
As evidence, the global `x` remains unchanged, and the local variable used its local scope variable to print the statements showing 11 as output through the function and 1 output by the global scope, as expected.
Also read: Comprehensive Guide to Python Built-in Data Structures
3. Modifying Global Variable Inside Local Scope
But is it possible to modify the global variable `x` without declaring it as `global`?
The answer is no! You cannot modify any global variable value from the local scope, as doing so will result in an error.
def h(y):
# Function can use global variable, if it doesn't have any
x += 10 # But cannot change the global value inside the local variable
x = 1
h(x)
print(x)
Output
UnboundLocalError Traceback (most recent call last)in ()
3
4 x=1
----> 5 h(x)
6 print(x)
in h(y)
1def h(y):
----> 2 x+=10
3
4 x=1
5 h(x)
UnboundLocalError: local variable `x` referenced before assignment
This results in an `UnboundLocalError` because Python treats `x` as a local variable due to the assignment operation, but it hasn’t been initialized locally. Also, though local variables can access global variables, you cannot make changes to the global variable (you can only read, not write).
Also read: Fundamentals of Python Programming for Beginners
4. Modifying Global Variable Inside Local Scope using Declaration
But since I have always told you that Python is actually a sweet language and even though it isn’t recommended to do any modification or changes on the global variable. That doesn’t mean Python doesn’t give you this functionality, as by declaring `x` as `global` using the same keyword, the function can modify the global variable `x`.
def h(y):
global x # Now it can change the global value inside the local variable
# But that isn't a good way of coding, you should focus on reducing this global keyword usage
x += 10
x = 1
h(x)
print(x)
Output
11
The output confirms that `x` has been updated globally. However, remember that the changes will affect the entire program, as modifying the main function will also affect other functions, which isn’t good programming practice.
5. Modifying Global Variable Inside Local Scope using Function
Also, you can modify the global variable inside the function `g(x)` by incrementing `x` by 10. It’ll print the new value and return it.
Note: This doesn’t mean that you are modifying the global variable itself, as it, anyway, isn’t possible without the `global` keyword.
def g(x):
x += 10
print("in f(x): x =" , x)
return x # Returning f(x)
x = 2
z = g(x)
print("in main program scope: z =", z)
print("in main program scope: x =", x)
Output
in f(x): x = 12in main program scope: z = 12
in main program scope: x = 2
Here, the global `x` remains unchanged, while the returned value `z` is the new updated value.
What are the Nested functions?
The functions that are defined inside another `def` function are called nested functions or inner functions.
Here is an example for a nested function for a better understanding:
def f():
def g():
print("Inside function g")
g()
print("Inside function f")
f()
Output
Inside function gInside function f
Note: The nested function `g` is called within the function `f`, printing messages from both functions. Calling function `g` outside the `f` will results in an error, since `g` is not defined in the global scope.
g() # This function is not defined outside the function f
Output
TypeError Traceback (most recent call last)in ()
----> 1 g()
TypeError: g() missing 1 required positional argument: 'x'
What is an Enclosing Scope of a Variable?
Python offers a different and special variable scope to only the names that are defined inside the nested function, known as an Enclosing Scope. It is also known as the `non-local` scope. Enclosing scope is the scope of the outer function when there is a local function, which is an inner or nested function.
def f():
x = 1
def g():
print("Inside function g")
print(x)
g()
print("Inside function f")
f()
This variable `x` is present inside the enclosing scope, which you can also use in local scope, as shown in above example. Here’s it output:
Output
Inside function g1
Inside function f
Now, let’s move ahead and understand this new scope better.
7. Modifying Global Variable Inside Enclosing Scope without Declaration
Again, modifying the global variable `x` inside the nested function is impossible.
def g(x):
def h():
x += 1
print('in h(x): x =', x)
x = x + 1
print('in g(x): x =', x)
h(x)
return x
x = 3
z = g(x)
print('in main program scope: x =', x)
print('in main program scope: z =', z)
Output
in g(x): x = 4---------------------------------------------------------------------------
TypeError Traceback (most recent call last)in ()
9
10 x=3
---> 11 z=g(x)
12 print('in main program scope: x =',x)
13 print('in main program scope: z =',z)
in g(x)
----> 7 h(x)
8 return x
9
TypeError: g..h() takes 0 positional arguments but 1 was given
As the function `h()`, is defined without any parameters, but `h(x)` is called with an argument. This will give a `TypeError`. Also, though the enclosing variable can access the global variable, you cannot perform changes in the global variable.
8. Modifying Nested Variable Inside Local Scope using Declaration
Similar, to as the `global` keyword, python offers its developers with a `nonlocal` keyword. That allows the nested function `h` to modify the variable `x` defined in the enclosing function `g`.
def g(x):
def h():
nonlocal x # Tell h() to use x from g(x)
x += 1
print('in h(x): x =', x)
x = x + 1
print('in g(x): x =', x)
h() # Call h() without any arguments
return x
x = 3
z = g(x)
print('in main program scope: x =', x)
print('in main program scope: z =', z)
Output
in g(x): x = 4in main program scope: x = 3
in main program scope: z = 5
The outputs show the changes made within both functions and that the global variable `x` remains unchanged.
Lastly, note that depending upon where the scopes are defined, each scope corresponds to different levels of access throughout the program and will have different lifespans for namespace/s within the code.
Also read: A Complete Python Tutorial to Learn Data Science from Scratch
Conclusion
This article explored how Python handles local and global variables and nested functions. We have learned that a namespace is a dictionary that Python offers developers, from which you can find a variable name and its value stored in the scope of Python memory. Further, the Scopes are of four types: local, enclosing, global, and built-in.
These are really useful for avoiding naming conflicts and for keeping track of which names/identifiers refer to which objects throughout the program’s different parts.
Also, if you want to modify a variable in the global scope from the local scope, you can use the `global` keyword. Similarly, you can use the `nonlocal` keyword to close the scope.
- Local scope: Variables created inside a function, accessible only within that function, and deleted when the function returns or any exception is raised, i.e., not handled while writing the function.
- Enclosing or Non-Local scope: Variables created in the outer function of nested functions, accessible to the inner function.
- Global scope: Variables created in the `__main__` program, accessible throughout the program and last until the interpreter ends.
I hope this has helped you gain insights into writing good production-level codes while following industry-related best practices and reducing developer-defined exceptions. However, this is the first step towards making our program more robust, and we have much more to cover.
So, stay tuned for the next article, where we’ll discuss File Serialization and Deserialization in the Python Programming Language!
Frequently Asked Questions
Ans. Namespaces in Python organize and manage the names or identifiers in a program. Basically, they act like containers or dictionaries that store names mapped to their objects, such as variables and functions.
Ans. The LEGB rule in Python is the order in which a Python Interpreter looks up while working with the names or commonly known as identifiers. It stands for Local, Enclosing, Global, and Built-in:
1. Local: Names defined within a function.
2. Enclosing: Names in the local scope of any enclosing function (nested function).
3. Global: Names defined at the top level of a script or module.
Built-in: Names that are pre-defined in Python, such as `print` or `len`.
Ans. Global keyword allows a function to modify a variable defined in the global scope and enables the variables to reside outside of the operation. Note: Just because you can do it, doesn’t mean you should use this (often), because it is not a good programming practice.
Ans. Overuse of global variables can lead to programs that are difficult to understand and maintain. It can also cause unintended changes, making debugging more difficult. It is generally better to use local variables and pass them as needed.
Ans. Similar to global keywords, Python offers `nonlocal` keywords to modify enclosing variables. The non-local keywords can modify variables defined in the enclosing function of a nested function, providing a way to control variable scope in nested functions.