Variable Scope: A Fundamental Programming Concept That No Python Programmer Must Ignore
A simple and intuitive guide to Python scope and LEGB rule.
In yesterday’s post, we discussed a fundamental difference between for-loops and list comprehension in Python.
Here’s the visual from that post for a quick recap:
In a gist:
After running a for-loop, the loop variable is still accessible.
After running a list comprehension, the loop variable is NOT accessible.
As I mentioned yesterday, this is closely linked to the idea of scope in Python, so let’s understand it today.
What is variable scope and why is it needed?
Simply put, variable scope refers to regions of our program in which a particular variable can be accessed.
The above idea is not specific to Python. Instead, it is valid for programming in general.
The objective is to limit variable access to only specific areas of our code so that we can prevent modifying variables from any random part of the program.
Thus, when we access ANY variable, it is scope that entirely determines how the names will be looked up in our code.
In Python, specifically, scope resolution has four levels.
Whenever we access any name in Python — a variable name, function name, class name, etc., the Python interpreter searches it in the following order:
Local
Enclosing
Global
Built-in
This is often called the LEGB rule.
LEGB scope resolution in Python
Let’s understand them one by one!
#1) Local scope
The simplest example of local scope would be variables declared inside a function, as depicted below:
The variable myVar
has a local scope in funcA
, which means that it can only be accessed inside the function.
If we try to access myVar
outside funcA
, we, expectedly, get an error because the variable is local to funcA
:
Moving on, if we have two non-enclosed functions, we notice that the variables declared inside one function are not accessible inside the second function:
This is the idea of local scope, and in Python, it gets the highest priority during scope resolution.
In other words, if the same variable name exists at multiple places in a program, Python will resort to the specific variable that was in the local scope from where it was accessed.
For instance, in the code below, myVar
is declared in both funcA
and funcB
. When we invoke funcA()
, Python finds myVar
in the local scope and prints it:
If the variable is found in the local scope, great.
If not, it moves to the enclosing scope (if any) to find the variable.
Before we move to enclosing scope…
One thing to always remember about local scope is that it is created at every function call, i.e., it is not created when the function is defined.
Thus, one can have as many distinct local scopes as the number of times they invoke a function, including recursive calls.
#2) Enclosing scope
In Python, the enclosing scope is defined when we have nested functions — one or more functions inside another function.
For instance, consider the latest code above. Let’s declare funcB
inside funcA
.
The local and enclosing scope with respect to funcB
is shown below:
Now consider the following code, where myVar
is not available in the local copy of funcB
:
As the local scope has no myVar
variable, it will first check if there’s any enclosing scope.
Yes, there is — funcA
!
Next, it will check if there’s myVar
declared inside funcA
.
Of course, there is!
Python refers to the value declared in the enclosing scope for myVar
:
In the above code, if there was no
myVar
declared insidefuncA
, Python would have moved to the Global scope, which comes next in the priority order.
#3) Global scope
Global scope, as you may have already guessed, is the broadest scope.
Here, variables and functions are declared outside any specific block, function, or class.
This makes them accessible (not directly modifiable though) from any part of the program, regardless of where they are defined.
For instance, in the code below, neither funcA
nor funcB
have myVar
variable defined in their respective local scope:
There is no enclosing scope either.
Thus, Python finds if myVar
is available in the global scope, and it is indeed available.
Thus, during the print
statements, we get the global value of myVar
— 10.
As an exercise, can you tell the output in this case:
#4) Built-in scope
The last in the priority order of scope resolution is built-in.
These are variable names that are automatically loaded in the global Python scope when we:
either run a script,
or open an interactive Python session.
These built-in variables can be accessed using the __builtins__
name, and there are >150
of them:
Some common examples include float
, int
, len
, set
, dict
, range
, str
, zip
, and more.
If a variable is not found in the local scope, not in the enclosing scope, and not even in the global scope, Python tries to find it in the built-in scope.
And that is how scope resolution works in Python.
Now, let’s go back to the list comprehension vs. for loop example.
The loop variable (loop_var
) is not accessible after running list comprehension because it is defined in its local scope.
However, the loop variable is defined in global scope in for-loop in the above code. Thus, it is still accessible after running the loop.
Hope you learned something new today.
👉 Over to you: Can you tell how we can modify a global variable in the local scope of a function?
👉 If you liked this post, don’t forget to leave a like ❤️. It helps more people discover this newsletter on Substack and tells me that you appreciate reading these daily insights.
The button is located towards the bottom of this email.
Thanks for reading!
Latest full articles
If you’re not a full subscriber, here’s what you missed last month:
DBSCAN++: The Faster and Scalable Alternative to DBSCAN Clustering
Federated Learning: A Critical Step Towards Privacy-Preserving Machine Learning
You Cannot Build Large Data Projects Until You Learn Data Version Control!
Sklearn Models are Not Deployment Friendly! Supercharge Them With Tensor Computations.
Deploy, Version Control, and Manage ML Models Right From Your Jupyter Notebook with Modelbit
Gaussian Mixture Models (GMMs): The Flexible Twin of KMeans.
To receive all full articles and support the Daily Dose of Data Science, consider subscribing:
👉 Tell the world what makes this newsletter special for you by leaving a review here :)
👉 If you love reading this newsletter, feel free to share it with friends!
Thank you for explaining this concept in such an easy way! Kudos to you!
This was beautifully illustrated, I needed this refresher lol