When we write a program in Python language, it is important to understand the concept of namespaces and scope. Both terms are closely related and are used to access variables, functions, and other objects in the program.
A namespace in Python is a mapping of names to objects in a program. It is a system that contains unique names for each and every object in Python. It is basically a container that has all the names of variables, functions, classes, or any other objects that we define.
The main purpose of using namespaces is to differentiate and organize the names based on their context. Namespaces help to avoid naming conflicts and to organize code in a structured manner.
Since Python is a dynamically typed language therefore, it manages its vast collection of objects with the help of namespaces. Python implements namespaces in the form of dictionaries.
So, we can define a namespace as:
A namespace is a dictionary object that contains variable names as keys and their corresponding objects as values. The pairs of key-value in a namespace are called bindings. A namespace simply tells Python where to find the object associated with a variable name.
Every object in Python belongs to a unique namespace. Whenever we create a new variable or function, Python adds it to a specific namespace.
This namespace helps Python understand which names correspond to which objects during the execution of a program. Python automatically and invisibly creates, updates, and deletes these namespaces during the execution of a program.
Types of Namespaces in Python
Python supports three types of namespaces to keep the track of variables at runtime. They are as:
- Built-in namespace
- Global namespace
- Local namespace
The below figure shows the hierarchy of namespaces in Python.
Let’s understand each namespace one by one with the help of example.
Built-in Namespace
In the hierarchy of namespaces, the top layer is a built-in namespace. Python automatically creates a built-in namespace when we start the interpreter. This namespace contains a pair of key-value for each of built-in functions and exceptions names that are always available by default in Python.
For example, built-in functions, such as print(), len(), tuple(), type(), etc are all belonging to this namespace and are available across all files and modules in Python.
To get the built-in namespace, just type dir(__builtin__) that will return a stored list of names in built-in namespace. You can also type vars(__builtin__) to return a dictionary corresponding to the built-in namespace.
Global Namespace
The middle layer is global namespace defined within a Python script, file, or module. When we load a module through import, Python creates a new global namespace. The global namespace contains a key-value pair for each top-level variable (also called global variable), function, class, and imported module.
Variables defined at the top level of a Python script or module come to the global namespace. They are accessible throughout the entire script or module.
Each module has its own global namespace, which Python deletes when the interpreter stops execution of the program. To get the global namespace, just type globals() that returns a dictionary corresponding to the current global namespace.
Local Namespace
Local namespace is at the bottom layer, which includes names defined within a class method or function. When we call a function, Python creates a new local namespace.
This local namespace contains a key-value pair for each function parameter and each local variable defined in the body of the function. So, we can say that any variable defined within a function has a local namespace.
These variables are only accessible within the function in which they are formed. A variable declared with a global keyword in a function does not come in this new local namespace. It comes in the global namespace.
Each function has its own local new namespace, which Python deletes when the function returns a value or throws an exception. To get the local namespace, just type local() that returns a dictionary corresponding to the current local namespace. For example:
Example 1:
x = "global" # global variable. def func(): x = "local" # local variable print(locals()) func()
Output: {'x': 'local'}
Scope in Python (Accessing Namespaces)
Python maintains multiple namespaces at runtime, and each with its own scope. A scope is a region or portion of the program where a namespace is visible and accessible. In simple words, the layer of namespace is called scope.
In Python, a scope determines the visibility and accessibility of names within a program. There are three types of scopes in the Python programming language.
- Local scope
- Global scope
- Built-in scope
Local scope:
A local scope is the region of the program where a variable or function is only accessible within a block or function. These types of variables and functions are defined in the local namespace and are not visible outside the of it.
Global scope:
A global scope is the region of the program in which a variable or function is accessible from anywhere. These types of variables and functions are defined global namespace and are visible throughout the entire program.
Let’s understand the concept of namespaces and scope of a function in Python with the help of important examples.
Example 2:
# Declaration of global variable. x = 20 def funct(y): z = x + y # Here y is a local variable and x is a global variable. return z result = funct(10) print(result)
Output: 30
In this example, we have defined a global variable named x outside the function funct(). Inside the function, we have defined a local variable, which is a parameter to this function. We have also defined a local variable z which stores the result of the sum of x and y.
When we call the funct() function with passing an argument 10, the value of z is computed and returned the result to the calling function. The returned result is stored in the variable result and then printed on the console.
As you can see in this example, the global variable x is accessible inside the function and we have used it in our computation. However, the variables y and z both are local variables and are only accessible within the function.
Example 3:
# Declaration of global variable. x = 20 def funct(y): z = x + y # Here y is a local variable and x is a global variable. # Accessing local variable z from the outside its scope. print(z)
Output: NameError: name 'z' is not defined
In this example, we have accessed a local variable z from outside the function. Therefore, we have gotten an error.
Enclosing scope:
This scope refers to the scope of enclosing function or block of code. It allows us to access names from the outer scopes but not from the global scope.
Built-in scope:
This scope represents the built-in namespace and includes the names which are available globally without any explicitly imports.
Scoping Rules to find Names in Namespace
Each time a function executes, a new namespace known as local namespace is created. This namespace represents a local environment that includes the names of function parameters, and names of variables created on the left-hand side of the assignment operator inside the function body.
These variables refer to the local variables because they have been defined inside the function and are part of local namespace. Python follows the LEGB rule to resolve names or to determine the scope of names of variables.
The rule stands for Local, Enclosing, Global, and Built-in. This rule defines a specific order in which Python interpreter searches to find a particular name. The interpreter checks the LEGB rule to search names in the following order:
(1) Local scope: The interpreter first checks the current local scope. If the interpreter finds a match in the current local scope (i.e. local namespace), it stops searching and uses that match.
(2) Enclosing scope: If interpreter does not finds a match in the local scope, it continues to search to the enclosing scope (if any).
(3) Global scope: If the interpreter does not find any match in the local and enclosing scope, it searches in the global scope or namespace.
(4) Built-in scope: If a match is still not found, the interpreter final searches in the built-in scope or namespace which contains Python built-in functions, types, and exceptions. If it fails here, Python raises an exception named NameError.
Example of Scoping Rules
Let’s take an example to understand the LEGB rule.
Example 4:
# An example of LEGB rule. x = "global" # global variable. def outer_func(): x = "enclosing" # local variable def inner_func(): x = "local" # local variable print(x) inner_func() outer_func() print(x)
Output: local global
In this example, we have defined a variable x in three different scope: global, enclosing, and local. The outer_func() function has enclosing scope as it encloses the inner_func() function.
When we call inner_func() function, Python first searches for the variable name x in its current local namespace and finds it. Since it is available in its local scope or namespace, it prints out the value “local”.
If Python does not find it in its local scope, it would then search in the enclosing scope of outer_func() function. If the interpreter does not find there, it would look in the global and built-in namespaces.
When we call outer_func() function, it does not display anything on the console because it does not have a print statement. Although, it has defined the variable name x in its enclosing scope. At last, the last print statement outside of function displays the value of variable x in the global namespace, which is “global”.
Thus, it is important to understand the LEGB rule to avoid variable name collisions, as well as to understand how Python searches and resolves variable names.
In this tutorial, we have discussed namespaces and scope in Python with the help of examples. By understanding namespaces and scope, we can effectively organize our code, avoid naming conflicts, and control the accessibility of variable names. Hope that you will have understood the basic points of namespaces in Python and practiced all examples.
Thanks for reading!!!