Understanding Python Namespaces and Scopes: A Comprehensive Guide
Written on
Chapter 1: Introduction to Namespaces
Have you ever been curious about how Python tracks all the objects you assign to symbolic names? Or why a variable defined inside a function doesn't affect a variable with the same name outside of it? In this section, we will explore the concept of namespaces in Python.
A namespace can be thought of as an organizational system for symbolic names linked to objects within a Python program. It serves as a repository where names are stored. By understanding the specific namespace and its associated scope, Python can identify which object you're referring to when you use a symbolic name.
When you assign a symbolic name (for instance, x = "hello world"), you're merely creating a reference to an object. The intriguing part is how Python determines which object you're referencing.
This video, "Python Tutorials - Namespace and Variable Scope," provides a detailed overview of how namespaces function in Python.
Section 1.1: Defining Namespaces
Python employs a technique called name resolution to ascertain the value associated with a symbolic name. Before calling a symbolic name, it must be assigned to an object. For instance, if we try to call c before it's assigned, Python will raise a NameError:
>>> print(c)
NameError: name 'c' is not defined
However, if we assign a value to c correctly:
>>> c = "This will work"
>>> print(c)
This will work
The scope in which we assign this symbolic name matters. In the above example, since we assigned c at the top level, it resides in what is called the global scope. To see the assignments in the global scope, you can print globals():
>>> c = "This will work"
>>> print(globals())
{'In': ['', 'c = "This will work"', 'globals()', 'print(globals())', ...}
Essentially, when we assign the string "This will work" to c, Python stores this object instance and the object itself as a key-value pair in a global dictionary. Thus, a namespace can be viewed as a standard dictionary structure where the key is the symbolic name and the values are the objects.
It’s important to note that the global namespace isn’t the only one present in a Python program. Each time you call an object, Python traverses through a series of namespaces during the name resolution process. Let's delve into the various namespaces available in Python: built-in, global, and local.
In the video titled "What are SCOPES and NAMESPACES in Python?", we delve deeper into these concepts.
Section 1.2: Types of Namespaces
Built-in Namespace
The built-in namespace contains all the built-in functions and exceptions that come with Python. For example, you can view its contents by executing:
>>> print(dir(__builtins__))
['ArithmeticError', 'AssertionError', 'AttributeError', ...]
This namespace is accessible throughout the entire duration of a Python program, existing until the program terminates.
Global Namespace
The global namespace consists of symbolic names defined at the top level of a Python program. It remains available for the entire execution of the program. You can see the objects defined globally by using dir():
>>> print(dir())
['In', 'Out', '_', '_10', ...]
When you import a module, a global namespace is created for that module:
>>> import sklearn
>>> print(vars()["sklearn"])
<module 'sklearn' from '...'>
Local Namespace
A new local namespace is created whenever a function is called:
>>> def example():
... c = "I want to change the value of c"
... return c
The local namespace only exists during the function's execution and is discarded once the function completes.
When variables are assigned within a function, they are confined to that function's local scope. For instance, if you have a variable c defined globally and another c defined inside a function, they won't interfere with each other:
>>> c = "This will work"
>>> def example():
... c = "I want to change the value of c"
... return c
>>> print(c)
This will work
>>> print(example())
I want to change the value of c
>>> print(c)
This will work
>>> c = example()
>>> print(c)
I want to change the value of c
Understanding Scopes
Now that we’ve explored namespaces, it’s vital to understand scopes, which define the accessibility of Python objects. When two instances share the same name but exist in different scopes, they won't conflict with one another. Python uses scopes to differentiate between references at runtime, ensuring clarity about which instance you're calling.
The order in which Python searches for a reference is as follows:
- Local
- Global
- Built-in
This order is referred to as name resolution or the LGB rule. Python searches in the local scope first, followed by the global scope, and finally the built-in scope. The search concludes when an instance is found, and if none is found, a NameError is raised.
Thank you for reading this guide on Python namespaces and scopes. Stay tuned for more insightful content!