Namespace and Scope in Python
What is Namespace in Python?
In Python, a namespace is a container that holds a set of identifiers (variable names, function names, class names, etc.) and their associated objects. It serves as a mapping between the names used in your Python program and the objects they refer to. Understanding namespaces is crucial for writing clean and organized Python code.
Python uses namespaces to manage the scope and lifetime of variables and other identifiers. Namespaces help prevent naming conflicts and enable you to organize your code effectively.
Types of Namespaces
The following Venn Diagram encompasses the various types of namespaces:
Global
The Global Namespace consists of all variables defined at the main level of the program. If the Python file is being used as a module (via the import) statement, then the global variables defined in that file are also imported and can be used accordingly.
Output:
Using global variables from imported files:
In mathematics.py
In main.py
After running main.py, we get the output –
Make sure that both mathematics.py and main.py are in the same folder!
Local
A Local Namespace gets created when a local function is invoked. Objects declared in this namespace cannot be used outside the function.
The above displays the behavior of a local variable.
Built-in
The built-in namespace contains predefined/built-in functions and objects. The scope of built-ins is the same as the lifetime of the entire program.
The following are some examples of built-ins:
- dict
- enumerate
- eval
- input
- id
- list
- int
These namespaces form the following scope hierarchy: Local > Global > Built-In
If there are 2 or more variables with the same name, the variable higher in the scope hierarchy will be used. These namespaces aren’t separate concepts. Instead, the local namespace is a subset of global, and the global namespace is a subset of built-in.
The most restricting namespace (local) is invoked during execution.
What is scope in Python
In Python, scope refers to the region in your code where a particular identifier (variable, function, class, etc.) is accessible. Understanding scope is crucial for writing Python programs that behave as expected and avoid naming conflicts.
Python defines the following main types of scope:
-
Local Scope: A local scope refers to the innermost level of scope, typically within a function or method. Variables defined in a local scope are only accessible within that function or method. Once the function or method exits, the local scope is destroyed, and the variables cease to exist.
-
Enclosing (Non-Local) Scope: In Python, functions can be nested within other functions. When a variable is not found in the local scope of a function, Python searches in the enclosing scopes, moving outward until it finds the variable or reaches the global scope. This is known as the enclosing or non-local scope.
-
Global Scope: The global scope encompasses the entire module. Variables defined at the top level of a module (outside of any function or class) belong to the global scope and are accessible from any part of the module.
-
Built-in Scope: The built-in scope contains Python's built-in functions, exceptions, and objects. These are available globally and do not require any import statements.
It's important to note that variables defined in a narrower scope can "shadow" variables with the same name in a broader scope. In such cases, the inner variable takes precedence.
Lifetime of Namespace
In Python, a namespace is a container that holds a set of identifiers (variable names, function names, class names, etc.) and their associated objects. Understanding the lifetime of a namespace is crucial for managing the availability of these identifiers throughout the execution of a Python program.
The lifetime of a namespace can be categorized into the following aspects:
-
Built-in Namespace Lifetime: The built-in namespace, which contains all the built-in functions, exceptions, and objects, exists throughout the entire lifetime of a Python program. These identifiers are available from the moment Python starts executing and remain available until the program terminates.
-
Global Namespace Lifetime: The global namespace, specific to a module, is created when the module is imported or executed. It exists as long as the Python interpreter is running. Variables and functions defined in the global namespace are accessible throughout the execution of the module.
-
Local Namespace Lifetime: Local namespaces are created when a function or method is called and exist only during the execution of that function or method. Once the function exits, the local namespace is destroyed, and the identifiers within it cease to exist.
-
Dynamic Namespace Creation: In Python, namespaces can also be created dynamically using constructs like comprehensions and generator expressions. These namespaces are short-lived and exist only during the execution of the expression.
Understanding the lifetime of namespaces is essential for managing memory efficiently and avoiding unintended side effects in your Python programs. When a namespace's lifetime ends, the associated memory is typically reclaimed by Python's garbage collector.
Examples of Namespace in Python
Example 1 – Behavior of local variables
Output:
Example 2 – Using global variables within functions
Output:
Example 3 – Nested Functions
Output:
Note: how foo2 is a local function, which cannot be accessed outside foo1()
Also, foo2() created a new local variable a and assigned the integer 2. After printing this variable, we incremented it. When control reached the second print statement, it printed 1, since the ‘inner’ local variable got incremented and not the one directly under foo1().
Example 4 – Manipulating Nonlocal Variables
Ouptut:
Because we declared 'a' as a nonlocal variable under foo2(), the variable under foo1() got updated. This means that 'a' did not get mapped to the new namespace under foo2().
Example 5 –
Confusingly, we can use built-in keywords as identifiers in Python, which is something that most conventional languages don’t allow. In practice, this is avoided to make code readable, but it displays the concept of namespace and scope elegantly with the built-in namespace, as seen in the following example.
Output:
int and input are used as local variables in foo() and as built-in objects outside foo().
Similarly, we can define int as a global variable and use it as a normal identifier. Try that out as an exercise!
As a side note, make sure to use global variables only when necessary. If used without care, things can get wrong very quickly, and errors can be hard to trace. Your code also becomes more unreadable as the number of unnecessary global variables increases.
What is Scope of Object in Python?
In Python, the scope of an object refers to where in your code an object is accessible and can be used. The scope of an object depends on how it is defined and where it is declared within your Python program.
Let's explore the scope of objects in Python with examples:
1. Global Scope:
Objects defined at the top level of a module are in the global scope. They are accessible throughout the module and can be used from any part of the module.
In this example, global_var is in the global scope, so it can be accessed both inside and outside the my_function.
2. Function Scope:
Objects defined within a function are in the function's local scope. They are only accessible within that function and are not visible outside of it.
Here, local_var is in the local scope of my_function, so it can only be accessed within that function.
3. Nested Scope:
In Python, functions can be nested within other functions. Objects defined in an outer function's scope are accessible within inner functions as well.
In this example, outer_var is in the scope of outer_function, and it can be accessed by the nested inner_function.
4. Class Scope:
Objects defined within a class are in the class's scope. They are accessible using instances of the class or by referencing the class itself.
Here, class_var is in the scope of the MyClass class, and it can be accessed both through instances and the class itself.
Conclusion
- Namespaces hold identifiers like variables, functions, and classes.
- Scope defines where a namespace can be accessed.
- Understanding namespaces and scope helps avoid naming conflicts.
- Proper use of namespaces and scope leads to efficient and maintainable programs.
- Python has four types of namespaces: built-in, global, local, and nonlocal.
- The LEGB rule defines the order in which Python searches for a variable in different namespaces.
- Global and local namespaces are created automatically in Python programs.
- Nonlocal namespaces are used to access variables in the enclosing scope of a nested function.