Recommended Video Course
Navigating Namespaces and Scope in Python
Table of Contents
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding:Navigating Namespaces and Scope in Python
A Pythonnamespace is a mapping from names to objects. It works like a dictionary where keys are object names and values are the objects themselves. Namespaces organize variables and functions in a dedicated space, allowing you to use multiple instances of the same name without conflict, as long as they’re in different namespaces.
In this tutorial, you’ll explore the different types of namespaces in Python, including the built-in, global, local, and enclosing namespaces. You’ll also learn how they define the scope of names and influence name resolution in Python programs.
By the end of this tutorial, you’ll understand that:
Understanding how namespaces work will improve your ability to manage and organize code efficiently in Python programs, helping to prevent name conflicts and other issues. To get the most out of this tutorial, you should be familiar with Pythonvariables andfunctions. Knowledge ofinner functions andclosures will also be a plus.
Get Your Code:Click here to download the free sample code that you’ll use to learn about namespaces and scope in Python.
Take the Quiz: Test your knowledge with our interactive “Namespaces in Python” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Namespaces in PythonIn this quiz, you'll test your understanding of Python namespaces. These concepts are crucial for organizing the symbolic names assigned to objects in a Python program and ensuring they don't interfere with one another.
Anamespace is a container that holds the currently defined symbolic names and the objects each name references. You can think of a namespace as adictionary, in which the keys are object names and the values are the objects themselves. Each key-value pair maps a name to its corresponding object.
Namespaces let you use the same name in different contexts without collisions. It’s like giving everything its own little room in a well-organized house. They allow Python to keep things organized, prevent naming conflicts, support the concept ofscope, and enforce modularity.
Namespaces are so crucial in Python that they were immortalized inThe Zen of Python:
Namespaces are one honking great idea—let’s do more of those!
—Tim Peters
As Tim Peters suggests, namespaces aren’t just great. They’rehonking great, and Python uses them extensively. Depending on how you structure your code, a Python program can have up to four different types of namespaces:
These namespaces have differing lifetimes. As Python executes a program, it creates namespaces as necessary and removes them when it no longer needs them. Typically, many namespaces will exist at any given time.
The Python global, local, and nonlocal namespaces are implemented as dictionaries. In contrast, the built-in namespace isn’t a dictionary but a module calledbuiltins
. This module acts as the container for the built-in namespace.
In the following sections, you’ll learn about these four namespaces and what their content and behavior are.
Thebuilt-in namespace contains the names of all of Python’s built-in objects. This namespace is available while the Pythoninterpreter is running. So, you can access the names that live in this namespace at any time in your code without explicitly importing them.
You can list the objects in the built-in namespace with thedir()
function using the__builtins__
object as an argument:
>>>dir(__builtins__)[ 'ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', ... 'super', 'tuple', 'type', 'vars', 'zip']
You may recognize some objects here, such asbuilt-in exceptions,built-in functions, andbuilt-in data types. Python creates the built-in namespace when it starts and keeps it active until the interpreter terminates.
Theglobal namespace contains the names defined at the module level. Python creates a main global namespace when the main program’s body starts. This namespace remains in existence until the interpreter terminates.
Additionally, each module has its own global namespace. The interpreter creates a global namespace for any module that your program loads with theimport
statement. For further reading on main functions and modules in Python, see the following resources:
For now, when you see the termglobal namespace, you can think of it as the one belonging to the main program.
To illustrate, get back to yourREPL session and run the following code:
>>>number=42>>>dir()[ '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', ... 'number']
In this code snippet, you define thenumber
variable as a global name. Then, you call the built-indir()
function to check the list of names defined in your current global scope. At the end of the list, you’ll find the'number'
key, which corresponds to your global variable.
The Python interpreter creates a new and dedicated namespace whenever you call a function. This namespace is local to the function and exists only until the function returns:
>>>defdouble_number(number):...result=number*2...print(dir())...returnresult...>>>double_number(4)['number', 'result']8>>>resultTraceback (most recent call last):...NameError:name 'result' is not defined>>>numberTraceback (most recent call last):...NameError:name 'number' is not defined
In this example, thenumber
argument and theresult
variable are local todouble_number()
. Note that if you try to access them after the function has returned, you getNameError
exceptions.
You can also define one function inside another. In this case, you’d have what’s known as aninner function. In the example below, you have the three scopes:
5>>>global_variable="global" 6 7>>>defouter_func(): 8...# Nonlocal scope 9...nonlocal_variable="nonlocal"10...definner_func():11...# Local scope12...local_variable="local"13...print(f"Hi from the '{local_variable}' scope!")14...print(f"Hi from the '{nonlocal_variable}' scope!")15...print(f"Hi from the '{global_variable}' scope!")16...inner_func()17...1819>>>outer_func()20Hi from the 'local' scope!21Hi from the 'nonlocal' scope!22Hi from the 'global' scope!
In this example, you first create a global variable at the module level. Then, you define a function calledouter_func()
. Inside this function, you havenonlocal_variable
, which is local toouter_func()
but nonlocal toinner_func()
. Ininner_func()
, you create another variable calledlocal_variable
, which is local to the function itself.
Each of these namespaces remains in existence until its respective function returns. Python might not immediately reclaim the memory allocated for those namespaces when their functions terminate, but all references to the objects they contain become invalid.
The existence of multiple, distinct namespaces allows you to have several different instances of a particular name simultaneously while a Python program runs. As long as each instance is in a different namespace, they’re all maintained separately and won’t interfere with one another.
That raises a question. Suppose you refer to the namex
in your code, andx
exists in several namespaces.How does Python know which one you mean each time?
The answer lies in the concept ofscope. The scope is the region of a program in which a name has meaning. The interpreter determines this at runtime based on where the name definition occurs and where the name is referenced in the code.
Note: See the Wikipedia page onscope in computer programming for an in-depth discussion of variable scope in programming languages.
You can also check out thePython Scope & the LEGB Rule: Resolving Names in Your Code tutorial, or get back to the fundamentals withPython Basics: Scopes.
The concepts of namespace and scope are closely related. In practice, namespaces are how Python applies the concept of scope to the name lookup process.
Returning to the question from the previous section, say that you’re referencingx
from inside an inner function. In this situation, Python looks forx
in the following order:
x
inside the inner function. If it doesn’t findx
there, then it moves to the enclosing scope.x
in the enclosing function’s scope. If it’s not found there, then it moves to the global scope.x
in the global scope. If it still doesn’t find it, it moves to the built-in scope.x
in the built-in scope. If it doesn’t findx
there, then it raises aNameError
exception.This is what’s known as theLEGB rule. The interpreter searches for a name from the inside out, looking in thelocal,enclosing,global, and finally, thebuilt-in scope:
If Python doesn’t find the name in any of these namespaces, then it raises aNameError
exception, as you’ve already learned. In the following sections, you’ll explore some examples that demonstrate how the LEGB rule works in practice.
In the example below, you define thex
variable outside bothouter()
andinner()
so it resides in your current global scope:
>>>x="global">>>defouter():...definner():...print(x)...inner()...>>>outer()global
The call toprint()
can only refer to one possiblex
. It displays thex
object defined in the global namespace, which holds the string"global"
.
In the next example, you definex
in two places: once in the global scope and once inside theouter()
function:
>>>x="global">>>defouter():...x="enclosing"...definner():...print(x)...inner()...>>>outer()enclosing
As in the previous example,inner()
refers tox
, but this time, it has two definitions to choose from:
x
in the global scopex
in the enclosing scopeAccording to the LEGB rule, the interpreter finds the value from the enclosing scope before looking in the global scope. Soprint()
displaysenclosing
instead ofglobal
.
Next, you definex
everywhere. The first definition is in the global scope. The second is insideouter()
but outsideinner()
. The third one is inside theinner()
function:
>>>x="global">>>defouter():...x="enclosing"...definner():...x="local"...print(x)...inner()...>>>outer()local
Now,print()
has to distinguish between three different possibilities:
x
in the global scopex
in the enclosing scopex
in the scope that’s local toinner()
In this case, the LEGB rule dictates thatinner()
first sees its own locally defined value ofx
, so theprint()
function displayslocal
.
Next, you have a situation whereinner()
tries to print the value ofx
, butx
isn’t defined anywhere. This results in an error:
>>>defouter():...definner():...print(x)...inner()...>>>outer()Traceback (most recent call last):...NameError:name 'x' is not defined
This time, Python doesn’t findx
in any of the namespaces, so theprint()
function generates aNameError
exception.
Shadowing or overriding names from the built-in namespace can be a common issue for beginners in Python. Built-in names are always available, and some could be suitable for real-world variables.
For example, say that you’re learning about lists and run the following code:
>>>list=[1,2,3,4]>>>list[1, 2, 3, 4]
In this example, you’ve usedlist
as the name for alist
object containing some numbers. This assignment overrides the built-inlist()
function:
>>>list(range(10))Traceback (most recent call last):...TypeError:'list' object is not callable
Now, callinglist()
fails because you’ve overridden the name in your previous code. A quick fix for this issue is to use thedel
statement to remove the custom variable and recover the original name:
>>>dellist# Remove the redefined name>>>list(range(10))[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
If you accidentally reassign a built-in name, then you can run a quickdel name
statement to remove the redefinition from your scope and restore the original built-in name in your working scope.
A more reliable approach would be to import thebuiltins
module and use fully qualified names:
>>>list=[1,2,3,4]>>>importbuiltins>>>builtins.list(range(10))[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
This time, even though you’ve overridden thelist
name, you can still use the original built-in function because of the fully qualified namebuiltins.list()
, which unambiguously refers to the object in the built-in namespace.
Python provides two built-in functions,globals()
andlocals()
, that allow you to access the global and local namespace dictionaries. These functions give you direct access to the content of both namespaces, which are implemented as dictionaries.
In the following sections, you’ll learn how to useglobals()
andlocals()
in your code. You’ll also get to know a critical difference between these built-in functions.
globals()
FunctionThe built-inglobals()
function returns a reference to the current global namespace dictionary. You can use it to access the objects in the global namespace. Here’s what it looks like when you start a REPL session:
>>>type(globals())<class 'dict'>>>>globals(){ '__name__': '__main__', '__doc__': None, '__package__': '_pyrepl', ...}
As you can see, the Python interpreter automatically adds several entries inglobals()
. Depending on your Python version and operating system, this may look a little different in your environment, but it should be similar.
Note: A closer look at the globals dictionary reveals a key called'__builtins__'
. This key maps to the content of thebuiltins
module or the built-in namespace. In practice, the__builtins__
variable in the global namespace holds a reference to thebuiltins
module.
Now, see what happens when you define a variable in the global scope:
>>>number=42>>>globals(){ '__name__': '__main__', '__doc__': None, ... 'number': 42}
After the assignment statementnumber = 42
, a new item appears in the global namespace dictionary. The dictionary key is the object’s name,number
, and the dictionary value is the object’s value,42
.
You would typically access this object in the usual way by referring to its symbolic name,number
. But you can also access it indirectly through the global namespace dictionary:
>>>number42>>>globals()["number"]42>>>numberisglobals()["number"]True
You can access the value ofnumber
using the dictionary key lookup syntax. Theis
operator in the final example confirms that these are the same object.
You can also useglobals()
to create and modify entries in the global namespace:
>>>globals()["message"]="Welcome to Real Python!">>>globals(){ '__name__': '__main__', '__doc__': None, ... 'number': 42, 'message': 'Welcome to Real Python!'}>>>message'Welcome to Real Python!'>>>globals()["message"]="Hello, World!">>>message'Hello, World!'
In this example, you first create a new global variable calledmessage
and assign a string to it. Then, you callglobals()
to inspect the namespace and find the new variable at the final position in the dictionary.
locals()
FunctionPython also provides a built-in function calledlocals()
. It’s similar toglobals()
, but it lets you access objects in the local namespace instead:
>>>deffunc(x,y):...message="Hello!"...print(locals())...>>>func(10,0.5){'x': 10, 'y': 0.5, 'message': 'Hello!'}
When called withinfunc()
,locals()
returns a dictionary representing the function’s local namespace. Notice that, in addition to the locally defined variables, the local namespace includes the function argumentsx
andy
since these are also local tofunc()
.
When you calllocals()
outside a function in the main program, it behaves the same asglobals()
, returning a reference to the global namespace:
>>>locals(){ '__name__': '__main__', '__doc__': None, '__package__': '_pyrepl', ... 'func': <function func at 0x104c87c40>}>>>globals(){ '__name__': '__main__', '__doc__': None, '__package__': '_pyrepl', ... 'func': <function func at 0x104c87c40>}>>>locals()isglobals()True
When you calllocals()
in the global namespace, you get a reference to the corresponding dictionary. In practice,locals()
behaves the same asglobals()
in this context.
globals()
andlocals()
There’s one slight difference betweenglobals()
andlocals()
that’s useful to know about. Theglobals()
function returns areference to the dictionary that contains the global namespace. Because of this, if you callglobals()
and save its return value, then you can add new variables and modify existing ones as you’ve already learned.
In contrast,locals()
returns a dictionary that’s acopy of the dictionary that holds the current local namespace rather than a reference to it. Because of this subtle difference, additions to the return value oflocals()
won’t modify the actual namespace:
>>>deffunc():...message="Hello!"...loc=locals()...print(f"{loc= }")...number=42...print(f"{loc= }")...loc["message"]="Welcome!"...print(f"{loc= }")...print(f"{locals()= }")...>>>func()loc = {'message': 'Hello!'}loc = {'message': 'Hello!'}loc = {'message': 'Welcome!'}locals() = {'message': 'Hello!', 'loc': {'message': 'Welcome!'}, 'number': 42}
In this example,loc
points to the return value oflocals()
, which is a copy of the local namespace dictionary.
The assignmentnumber = 42
adds a new variable to the local namespace butnot to the copy thatloc
points to. Similarly, the assignmentloc["message"] = 'Welcome!'
modifies the value for key"message"
inloc
, but doesn’t affect the local namespace.
Finally, it’s worth noting thatlocals()
returns a shallow copy of the namespace, so any name that points to a mutable object lets you change that object in place. This change is reflected in the local namespace:
>>>deffunc():...fruits=["apple","banana"]...loc=locals()...loc["fruits"].append("orange")...print(f"{loc= }")...print(f"{locals()= }")...>>>func()loc = { 'fruits': ['apple', 'banana', 'orange']}locals() = { 'fruits': ['apple', 'banana', 'orange'], 'loc': {'fruits': ['apple', 'banana', 'orange']}}
In this example, you keep a reference to thelocals()
return value inloc
. Then, you use this variable to append a new value to thefruits
list, which is mutable. This change affects the content of your local namespace, as you can see in the last highlighted line.
Sometimes, you try to modify a variable from an outer scope within a function. In a function, you can’t reassign a variable that points to an object defined on the outside and expect the change to affect that variable:
>>>x=20>>>deff():...x=40...print(x)...>>>f()40>>>x20
Here, you have a global variablex
with a value of20
. Whenf()
executes the assignmentx = 40
, it creates a new local variable whose value is40
. Because of this reassignment,f()
loses the reference tox
in the global namespace. So, the assignment doesn’t affect the global variable but creates a new local variable.
Note that whenf()
executesprint(x)
, it displays40
, the value of its own localx
. But afterf()
terminates, thex
variable in the global scope is still20
.
In contrast, a function can modify a mutable object from an outer scope:
>>>fruits=["apple","banana","cherry","mango"]>>>deff():...fruits[1]="peach"...>>>f()>>>fruits['apple', 'peach', 'cherry', 'mango']
In this example,fruits
is a list, and lists aremutable. You can change the list’s content insidef()
even though the list is defined outside the function’s scope.
Again, iff()
tries to reassignfruits
entirely, then Python will create a new local object and won’t modify the globalfruits
:
>>>fruits=["apple","banana","cherry","mango"]>>>deff():...fruits=["grapes","orange"]...>>>f()>>>fruits['apple', 'peach', 'cherry', 'mango']
In this example, you assign a differentlist
object to the namefruits
inside the function. This creates a local variable that shadows the global one. Therefore, changes to the localfruits
don’t affect the globalfruits
.
global
StatementWhat if you need to modify a value in the global scope from within a function? You can do this using the Pythonglobal
statement:
>>>x=20>>>deff():...globalx...x=40...print(x)...>>>f()40>>>x40
Theglobal x
statement indicates that whilef()
executes, references to the namex
will refer to thex
defined in the global namespace. That means the assignmentx = 40
doesn’t create a new local variable. It assigns a new value tox
in the global scope instead:
As you’ve already learned in previous sections,globals()
returns a reference to the global namespace dictionary. If you want, you can produce the same result usingglobals()
instead of theglobal
statement:
>>>x=20>>>deff():...globals()["x"]=40...print(x)...>>>f()40>>>x40
In this example, you directly modify the value of the globalx
using theglobals()
function and a dictionary key assignment. There isn’t a good reason to do it this way sinceglobal
makes the code cleaner and more readable.
If the name specified in theglobal
statement doesn’t exist in the global scope when the function starts, then a combination of theglobal
statement and an assignment creates it:
>>>yTraceback (most recent call last):...NameError:name 'y' is not defined>>>deff():...globaly...y=20...>>>f()>>>y20
In this case, when you callf()
, there’s no object namedy
in the global scope. Theglobal y
statement declaresy
as global, and the assignment in the next line creates the variable in the global namespace for you. However, this is an unusual a way to create global variables and it’s not a recommended practice.
Note: Using theglobal
statement is generally discouraged in Python. Modifying global variables can make code harder to follow and debug, as the variable’s value becomes unpredictable at different points during execution.
Check out theUsing and Creating Global Variables in Your Python Functions tutorial to learn more about this topic.
You can also specify several comma-separated names in a singleglobal
statement:
>>>x,y,z=10,20,30>>>deff():...globalx,y,z...
Here,x
,y
, andz
are all declared to refer to objects in the global scope by the singleglobal
statement on the highlighted line.
A name specified in aglobal
statement can’t appear in the function body before theglobal
statement:
>>>deff():...print(x)...globalx... File"<python-input-0>", line3globalx^^^^^^^^SyntaxError:name 'x' is used prior to global declaration
In this example, theglobal
statement makesx
refer to an object in the global scope. The call toprint()
refers tox
before theglobal
statement, which raises aSyntaxError
exception.
nonlocal
StatementA similar situation occurs with nested functions when you need to modify variables in the enclosing scope. Thenonlocal
keyword addresses this by referring to variables in the nearest enclosing scope, which allows you to modify them within the nested function:
>>>deff():...x=20...defg():...nonlocalx...x=40...g()...print(x)...>>>f()40
After thenonlocal x
statement, wheng()
accessesx
, it refers to thex
in the nearest enclosing scope, defined in the outerf()
function:
The call toprint()
at the end off()
confirms thatg()
has changed the value ofx
in the enclosing scope to40
.
It’s important to note that thenonlocal
keyword is only applicable in nested functions. You can only use it to access variables in the enclosing scope.
You’ve learned about Python namespaces, which map names to objects. You’ve also explored different types of namespaces, such as built-in, global, local, and enclosing, and learned how they define the scope of a name in Python.
Additionally, you delved into theLEGB rule, which defines how Python searches for names across the actual namespaces. You also learned how to modify variables from different scopes usingglobal
andnonlocal
statements.
In this tutorial, you’ve learned:
globals()
andlocals()
functionsglobal
andnonlocal
With these skills, you can now write more organized and efficient Python programs to ensure your code remains clean and versatile.
Get Your Code:Click here to download the free sample code that you’ll use to learn about namespaces and scope in Python.
Now that you have some experience with Python namespaces and scopes, you can use the questions and answers below to check your understanding and recap what you’ve learned.
These FAQs are related to the most important concepts you’ve covered in this tutorial. Click theShow/Hide toggle beside each question to reveal the answer.
A Python namespace is a container that holds symbolic names mapped to objects. It behaves similarly to a dictionary where keys are names and values are objects.
Python has built-in, global, local, and enclosing namespaces, each with its own purpose and scope within a program.
A namespace maps names to objects, while a scope is a region in your code where you can access a given name.
Python implements namespaces using dictionaries, with each namespace mapping names to objects within a particular scope.
The LEGB rule in Python stands for local, enclosing, global, and built-in. It describes the order in which Python searches for a name across different namespaces. This rule applies during the name resolution process.
Take the Quiz: Test your knowledge with our interactive “Namespaces in Python” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Namespaces in PythonIn this quiz, you'll test your understanding of Python namespaces. These concepts are crucial for organizing the symbolic names assigned to objects in a Python program and ensuring they don't interfere with one another.
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding:Navigating Namespaces and Scope in Python
🐍 Python Tricks 💌
Get a short & sweetPython Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.
AboutLeodanis Pozo Ramos
Leodanis is an industrial engineer who loves Python and software development. He's a self-taught Python developer with 6+ years of experience. He's an avid technical writer with a growing number of articles published on Real Python and other sites.
» More about LeodanisMasterReal-World Python Skills With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
MasterReal-World Python Skills
With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
What Do You Think?
What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.
Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students.Get tips for asking good questions andget answers to common questions in our support portal.
Keep Learning
Related Topics:intermediatepython
Recommended Video Course:Navigating Namespaces and Scope in Python
Related Tutorials:
Already have an account?Sign-In
Almost there! Complete this form and click the button below to gain instant access:
Namespaces and Scopes in Python (Sample Code)