Master Python variable scope and create crash-free programs with this detailed guide!
Python variable scope makes coding and debugging significantly easier than in any other previous programming language. It’s arguably one of the biggest reasons behind the language’s success over the years.
Python variable scope, in very few words, brings order to your code. Python scope allows you to compartmentalize your variable’s visibility and actions, allowing you to keep potential bugs and error values neatly contained into specific blocks of codes. It saves considerable time and effort and proves itself a game-changer when it’s time to debug your programs.
Python Variable Scope
A scope is, essentially, a container for variables, and these can only be seen or accessed in the container they were initially created. These containers follow Python variable scope’s main rule, known as the LEGB rule.
The LEGB rule stands for Local, Enclosing, Global, and Built-in scopes, also known as Python scope levels. Python will also try to resolve a variable and any functions assigned to it by sequentially checking the Local, Enclosing, Global, and Built-in scope (hence the rule’s acronym). One can reference PEP 3104 to detail how these dynamics have evolved over the course of Python’s developmental history.
As with almost any other concept in programming, Python variable scope is best explained with examples and actionable tips that you can test for yourself. Let’s diver deeper into the Local and Global scope and see how these two Python variable scope levels interact in programs along with some examples.
Python Local Variable
A variable that exists in a local scope is called a local variable, but what is the local scope? A local scope is created whenever a function is called. Any variables assigned in this function exist within the local scope, and can only be accessed from the point at which it was originally defined.
You’ll have as many local scopes as function calls, and each local scope gets deleted once the function returns. Variables that are assigned outside of all functions, on the other hand, exist in the global scope.
Global Scope Python
You enter Python’s global scope when you start a program. Any function, reference, or variable that exists in the global scope can be accessed from any other place in your code. A variable must be one or the other, it cannot be both local and global.
Just from the get-go, we can establish some Python scope rules.
- You can’t use any local variables in the global scope
- You can use global variables in the local scope.
- Code in a function’s local scope can’t access variables that exist in other local scopes.
- Multiple instances of the same variable can exist in different scopes. For instance, you can have a local variable named food, and a global variable also named food.
In this next example, I’ll put our first Python scope rule to the test. I’ll try to use a local variable in the global scope and see if it returns an error.
# "You can't use any local variables in the global scope" Demonstration #Defining my local_numbers function def local_numbers(): #Local Scope Begins Here local_number_1 = 10 # Returning to the Global Scope #Attempting to print my local_numbers_1 value from the Global scope print(local_number_1) Traceback (most recent call last): File "c:\Users\Dan\Desktop\Python Files\MoreExamples.py", line 12, in <module> print(local_number_1) NameError: name 'local_number_1' is not defined. Did you mean: 'local_numbers'?
As expected, we got an error. The error happens because the local_number_1 variable exists in the local scope that was created when we called the local_numbers() function.
Our program executed the function, just as we asked, but once it returned from local_numbers, the local scope was deleted, so the local_number_1 variable was no longer available.
This time, let’s try to print the local_number_1 variable within the function’s local scope.
# "You can't use any local variables in the global scope" Demonstration #Defining my local_numbers function def local_numbers(): #Local Scope Begins Here local_number_1 = 10 print (local_number_1) # Returning to the Global Scope # Calling my local_numbers function local_numbers() 10
Notice how defining a local variable is pretty much like creating a blueprint for a local scope. After all, the local scope will only exist when the function is called.
Now, let’s see if our rule #2 (using global variables in the local scope) is true.
Function Scope Python
Global variables are defined outside any function and can be accessed by any other function and corresponding local scopes.
Here’s an example of what a global variable looks like:
# Defining a global variable global_number_1 = 20 print(global_number_1) 20
Here’s what our global variable looks like, right below our earlier function’s local variable.
# Local function and its Local scope def local_numbers(): local_number_1 = 10 print (local_number_1) local_numbers() # Defining a global variable global_number_1 = 20 print(global_number_1) 10 20
Our first set of Python scope rules said: “you can use global variables in the local scope.” If that’s true, then we should be able to modify our local_numbers function and call on the variable global_number_1. Let’s give it a shot!
def local_numbers(): local_number_1 = 10 print (local_number_1) local_calculus = local_number_1 * global_number_1 print (local_calculus) local_numbers() # Defining a global variable global_number_1 = 20 print(global_number_1) Traceback (most recent call last): File "c:\Users\Dan\Desktop\Python Files\Scopes Examples", line 8, in <module> local_numbers() File "c:\Users\Dan\Desktop\Python Files\Scopes Examples", line 6, in local_numbers local_calculus = local_number_1 * global_number_1 NameError: name 'global_number_1' is not defined. Did you mean: 'local_number_1'?
Wait, what? Does this mean our second rule is wrong?
Not quite. Our error states: name ‘global_number_1’ is not defined. This means that our program tried to retrieve the variable global_number_1 before it was even defined. It’s a big reason why most global variables are defined at the top of our code.
Let’s re-organize this mess and give it a second try!
# Defining a global variable global_number_1 = 20 print(global_number_1) # Local function and its Local scope def local_numbers(): local_number_1 = 10 print (local_number_1) local_calculus = local_number_1 * global_number_1 print (local_calculus) local_numbers() 20 10 200
That’s much better. This time our variable local_calculus (which exists in local_numbers() local scope) was able to access a global variable (global_number_1) and used it for its calculations.
Global variables are fairly simple to understand and access, but as your programs get more and more complicated, you’ll notice that having variables that exclusively exist in a local scope is truly a blessing as well.
Having said that, let’s move on to our rule #3, which says that code in a function’s local scope can’t access variables that exist in other local scopes.
Python Scoping
As we mentioned earlier, a local scope is created once a function is called, and is subsequently deleted once the function returns. But, can we access local variables that exist in another function’s local scope?
In this next example, I’ll define two functions, each with its own variables and scopes. Then, I’ll try to retrieve one of the first function’s values and use it on my second local scope. Both variables are technically in a local scope, so it’s only fair that we give it a try.
def local_numbers_2(): local_number_2 = 30 print (local_number_2) local_numbers_2() def local_numbers_3(): local_number_3 = 40 local_result = (local_number_2 * local_number_3) print(local_result) local_numbers_3() Traceback (most recent call last): File "c:\Users\Dan\Desktop\Python Files\Scopes Examples", line 28, in <module> local_numbers_3() File "c:\Users\Dan\Desktop\Python Files\Scopes Examples", line 26, in local_numbers_3 local_result = (local_number_2 * local_number_3) NameError: name 'local_number_2' is not defined. Did you mean: 'local_number_3'?
This time, we’ve encountered a NameError, despite the fact that the variable local_number_2 was previously defined in our local_numbers_2 function.
Let’s remove the local_number_2 variable from the operation and see if the error persists.
def local_numbers_2(): local_number_2 = 30 print (local_number_2) local_numbers_2() def local_numbers_3(): local_number_3 = 40 local_result = (local_number_3) print(local_result) local_numbers_3() 30 40
As expected, both of our functions are now working. This proves that you can only access a local variable within its function local scope.
Now it’s time to test rule #4 in our initial Python scope rules list.
Scoping Python
Our rule #4 stated that multiple instances of the same variable can exist in different scopes. This means that, we could, for instance, define a local variable named global_number_2, as well as a global variable also called global_number_2 without resulting in name collision, right?
We’ll try that in our next example. We’ll assign an integer value of 20 to our global variable, and 10 to our local variable, and see which one gets printed.
# Defining a global variable global_number_2 = 20 #Defining a local variable with the same name def local_numbers(): global_number_2 = 10 print (global_number_2) local_numbers() 10
It seems that Python has prioritized and printed the value assigned in the local scope. This follows the principles stated in the LEGB rule (Local, Enclosing, Global, and Built-in scopes). Python sequentially checks each of these scopes in order to resolve a variable, and it found its match in the function’s local scope.
As you can already tell, it’s best to avoid naming local variables after global variables, since it can get in the way of debugging your programs. But, it’s nice to know that all of our initial set of rules stand.
So far, we’ve covered the “L” and “G” in the LEGB Python scope acronym, but what about the rest of our letters?
It’s time that we cover a third scope, one that exists within Python’s local and global scope.
Function Scope Python: Enclosing Scope
Enclosing scope appears when you nest functions inside other functions. The outer function will have its corresponding local scope, and it will simultaneously become the enclosing scope of the nested/inner function.
While this type of function scope Python sounds a bit confusing at first, its behavior and inner workings will become crystal clear in the next example.
For our enclosing scope example, we’ll define two functions: an outer function (with a variable) and an inner function. I’ll also plug in a few developer comments to help identify each of the function scope Python that interacts here.
# Defining a Global variable in the GLOBAL SCOPE global_variable = 100 def outer_function(): # The LOCAL SCOPE of our outer function starts here() # The ENCLOSING SCOPE of our inner function starts here() outer_function_variable = 200 def inner_function(): # The LOCAL SCOPE of our inner function starts here() print (outer_function_variable) print(global_variable) inner_function() outer_function() 200 100
A few things to unpack here:
You can use global variables on your nested functions.
- Your nested functions can use variables that exist in its enclosing scope.
- Your outer function’s local scope, is also your inner function’s enclosing scope.
Some coders refer to these functions as “enclosing” and “nested” functions to better understand function scope Python. I’ll rename our functions and variables to better illustrate how enclosing scope works.
# Defining a Global variable in the GLOBAL SCOPE global_variable = 100 def enclosing_function(): # The LOCAL SCOPE of our outer enclosing starts here() # The ENCLOSING SCOPE of our nested function starts here() enclosing_function_variable = 200 def nested_function(): # The LOCAL SCOPE of our nested function starts here() print (enclosing_function_variable) print(global_variable) nested_function() enclosing_function() 200 100
Same example and output as above, but with different names.
We can try to print a new nested_function() variable in its enclosed scope (also known as enclosing_function’s local scope), but we’ll encounter a NameError, because it hasn’t been defined yet.
# Defining a Global variable in the GLOBAL SCOPE global_variable = 100 def outer_function(): # The LOCAL SCOPE of our outer function starts here() # The ENCLOSING SCOPE of our inner function starts here() outer_function_variable = 200 outer_function_calculus = (outer_function_variable * inner_function_variable) def inner_function(): # The LOCAL SCOPE of our inner function starts here() inner_function_variable = 300 print (outer_function_variable) print(global_variable) inner_function() outer_function() Traceback (most recent call last): File "c:\Users\Dan\Desktop\Python Files\Python Scope Examples", line 39, in <module> outer_function() File "c:\Users\Dan\Desktop\Python Files\Python Scope Examples", line 31, in outer_function outer_function_calculus = (outer_function_variable * inner_function_variable) NameError: name 'inner_function_variable' is not defined
As expected, we can’t access a nested function’s local variables in its enclosed scope, because we haven’t defined them yet.
Does Python Have Global Variables
Yes, Python has global variables that you should define near the top of your code to avoid NameError crashes. But you can also use the “global” keyword, followed by the variable’s name, to transform a local variable into a global variable.
In the following example, I’ll create the variable “new_global_variable” within outer_function’s local scope, and use the global statement to turn it into a global variable.
Remember that this is also inner_function’s enclosing scope. I’ve purposely done this at this block of code to demonstrate that the global statement can be used in enclosing scopes as well.
Our new variable will take our initial global_variable and add +1 to it. I’ll print the new_global_variable value from within our inner_function’s scope. Since this is a global variable, I should be able to reference it from a function’s local scope without any issues. I’ll also print the new_global_variable value straight from the global scope for good measure.
# Defining a Global variable in the GLOBAL SCOPE global_variable = 100 def outer_function(): # The LOCAL SCOPE of our outer function starts here() # The ENCLOSING SCOPE of our inner function starts here() # Using the Global keyword to make new_global_variable a global variable within a local scope global new_global_variable new_global_variable = global_variable + 1 def inner_function(): # The LOCAL SCOPE of our inner function starts here() # Printing our new global variable from a local scope print(new_global_variable) inner_function() outer_function() # Printing our new global variable (created in a Local and Enclosing scope) from the Global scope print(new_global_variable) 101 101
As expected, we’ve successfully printed our new_global_variable value twice, once from inner_function’s local scope, and a second time from within the global scope.
Now that we know how to use the global statement, it’s time we tackle the last letter in the LEGB acronym: the built-in scope.
Variable Scope Python: The Built-in Scope
The built-in scope is an exclusive scope that contains Python’s special keywords such as False, True, for, def and many other special variables that are automatically loaded by Python when you run a program.
You can use the print(len(dir(__builtins__))) statement to count the number of built-in functions that Python automatically loads for you. As of today, there are 156 objects that Python defines for us on start up.
print(len(dir(__builtins__))) 156
Last Words
Understanding Python variable scope is one of the earliest and most fundamental steps you’ll take towards mastering this programming language. It ties directly into your code’s structure, effectiveness, and order all at once. Moreover, knowing its ins and outs will significantly cut down on your overall debugging times.
As always, you’re welcome to take this article’s code and tweak it (or experiment with it) in order to get a better understanding of how the LEGB rule works in Python. Having a solid understanding of the basics can save you a whole lot of headaches as you progress through your coding journey!