Basics Intermediate Advanced
aialgorithmsapibest-practicescareercommunitydatabasesdata-sciencedata-structuresdata-vizdevopsdjangodockereditorsflaskfront-endgamedevguimachine-learningnewsnumpyprojectspythonstdlibtestingtoolsweb-devweb-scraping
Recommended Course

Navigating Namespaces and Scope in Python
27m · 11 lessons

Namespaces in Python
Table of Contents
Recommended Course
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:
- Pythonnamespaces serve as containers thatmap names to objects, allowing for organized access and management of variables, functions, classes, and objects in general.
- Namespace and scope differ in that a namespace maps names to objects, while a scope is theregion of code where you can access a name.
- Pythonimplements most namespaces usingdictionaries, where each namespace’s lifecycle is tied to the execution context, such as global or local scopes.
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.
Getting to Know Namespaces in Python
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:
- Built-In
- Global
- Local
- Enclosing or nonlocal
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.
The Built-in Namespace
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.
The Global Namespace
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 Local Namespace
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 definedIn 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.
The Enclosing or Nonlocal Namespace
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.
Understanding the Scope of Names
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.
The LEGB Rule for Searching Names
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:
- Local: Python searches for
xinside the inner function. If it doesn’t findxthere, then it moves to the enclosing scope. - Enclosing: Next, Python searches for
xin the enclosing function’s scope. If it’s not found there, then it moves to the global scope. - Global: Python searches for
xin the global scope. If it still doesn’t find it, it moves to the built-in scope. - Built-in: Finally, Python searches for
xin the built-in scope. If it doesn’t findxthere, then it raises aNameErrorexception.
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.
The LEGB Rule in Action
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()globalThe 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()enclosingAs in the previous example,inner() refers tox, but this time, it has two definitions to choose from:
xin the global scopexin the enclosing scope
According 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()localNow,print() has to distinguish between three different possibilities:
- The
xin the global scope - The
xin the enclosing scope - The
xin 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 definedThis time, Python doesn’t findx in any of the namespaces, so theprint() function generates aNameError exception.
Shadowing Built-in Names in Python
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 callableNow, 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.
Managing Namespace Dictionaries
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.
Theglobals() Function
The 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"]TrueYou 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.
Thelocals() Function
Python 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()TrueWhen you calllocals() in the global namespace, you get a reference to the corresponding dictionary. In practice,locals() behaves the same asglobals() in this context.
The Difference Betweenglobals() 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.
Modifying Variables From a Different Namespace
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>>>x20Here, 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.
Theglobal Statement
What 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>>>x40Theglobal 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>>>x40In 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()>>>y20In 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 declarationIn 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.
Thenonlocal Statement
A 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()40After 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.
Conclusion
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:
- What anamespace is in Python
- How namespaces relate to the concept ofscope
- Which namespaces exist in Python, including thelocal,enclosing,global, andbuilt-in
- How Python applies theLEGB rule to resolve names in various scopes
- How to manage namespace dictionaries using the
globals()andlocals()functions - How to modify variables from different scopes using
globalandnonlocal
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.
Frequently Asked Questions
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.
Recommended Course
🐍 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 a self-taught Python developer, educator, and technical writer with over 10 years of experience.
» 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.
Looking for a real-time conversation? Visit theReal Python Community Chat or join the next“Office Hours” Live Q&A Session. Happy Pythoning!
Keep Learning
Keep reading Real Python by creating a free account or signing in:
Already have an account?Sign-In







