Python Scope of Variables
Table of Contents
In the last lesson, we learned about Python Lambda Functions. Now let’s understand where variables live and which parts of a program can use them.
Let’s Talk About Where Variables Live
Imagine we have a house. Inside the house, we have a kitchen. Inside the kitchen, we have a drawer. In that drawer, we keep a spoon.
Now, can someone in the living room use that spoon? Well, they would have to go to the kitchen, open the drawer, and take it. The spoon is not just lying around in the living room.
Variables in Python are like that. Each variable has a place where it lives. And where it lives determines who can use it.
That is what scope means. Scope is the area where a variable is accessible.
Why Does Scope Matter in Python?
Because if we do not understand scope, we will get confusing errors. We will try to use a variable outside the function where it was created. And Python will say, “I do not know what you are talking about.”
So let’s understand it properly.
The Four Levels of Scope in Python
Python has four levels of scope. They follow something called the LEGB rule.
- L — Local
- E — Enclosing
- G — Global
- B — Built-in
Let me explain each one.
Local Scope in Python
A variable created inside a function is local to that function. It lives inside the function. And it dies when the function finishes.
def my_function(): x = 10 print(x)
my_function()print(x) # Error!Output
10NameError: name 'x' is not definedSee what happened? Inside the function, x exists. We can print it. But outside the function, x does not exist. Python has never heard of it.
That is local scope. The variable is local to the function. It is born when the function runs. And it disappears when the function ends.
Think of it like this. We write something on a whiteboard in a meeting room. When the meeting is over, someone erases the board. The information is gone. It only existed inside that room.
Global Scope in Python
A variable created outside any function is global. It lives in the main part of our program. And it can be accessed from anywhere.
x = 10
def my_function(): print(x)
my_function()print(x)Output
1010Here, x is created outside the function. So it is global. The function can read it. And the main program can read it.
But here is the catch. We can read a global variable inside a function. But we cannot change it. Not without permission.
x = 10
def my_function(): x = 20 # This creates a new local variable print(x)
my_function()print(x)Output
2010Wait. Why did x stay 10 outside the function?
Because inside the function, x = 20 did not change the global x. It created a new local variable called x. They just happen to have the same name. But they are different variables.
Think of it like this. We have a friend named Alex. We also have a cousin named Alex. They are different people. Same name. Different people.
So inside the function, we created a new local x. The global x was not touched.
If we really want to change the global variable inside a function, we need to use the global keyword.
x = 10
def my_function(): global x x = 20
my_function()print(x)Output
20Now the global x is changed. Because we told Python: “I am talking about the global x, not a new local one.”
Let’s use global carefully. It can make our code confusing. Most of the time, we do not need it.
Enclosing Scope in Python
This one is about nested functions. A function inside another function.
def outer(): x = 10
def inner(): print(x)
inner()
outer()Output
10Here, x is in the outer function. The inner function can read it. Because it is in the enclosing scope.
But like before, if we try to change it, we need the nonlocal keyword.
def outer(): x = 10
def inner(): nonlocal x x = 20
inner() print(x)
outer()Output
20The nonlocal keyword tells Python: “I am talking about the x in the enclosing function, not a new local one.”
Again, let’s use it carefully.
Built-in Scope in Python
Python has some names built in. Like print, len, sum, max, min, and so on. These are always available. They are in the built-in scope.
print(len("hello"))We do not need to define print or len. They are just there. That is built-in scope.
The LEGB Rule in Python
When we use a variable, Python looks for it in this order:
- Local — inside the current function
- Enclosing — inside any enclosing function
- Global — at the top level of the module
- Built-in — Python’s built-in names
It stops at the first place it finds the name. So if we have a local x and a global x, the local one wins inside the function.
Let me show us.
x = "global"
def outer(): x = "enclosing"
def inner(): x = "local" print(x)
inner()
outer()Output
localBecause inner has its own local x. So that is what gets printed.
If we remove the local x:
x = "global"
def outer(): x = "enclosing"
def inner(): print(x)
inner()
outer()Output
enclosingNow Python looks in local scope. No x. Then enclosing scope. Finds x. So it prints “enclosing”.
If we remove the enclosing x:
x = "global"
def outer(): def inner(): print(x)
inner()
outer()Output
globalNow Python looks in local. No. Enclosing. No. Global. Finds it. Prints “global”.
That is the LEGB rule. It always searches in that order.
Python Scope: A Real-Life Example
Let’s say we are building a simple game. We have a global variable for the score.
score = 0
def add_points(points): global score score += points print(f"Score is now {score}")
add_points(10)add_points(5)print(f"Final score: {score}")Output
Score is now 10Score is now 15Final score: 15Here, we need global because we are changing the global score from inside the function.
Without global, score += points would create a local score. And the global would stay 0.
A Better Way
Actually, using global is often a sign of bad design. A better way is to return the new value and assign it outside.
score = 0
def add_points(current_score, points): return current_score + points
score = add_points(score, 10)score = add_points(score, 5)print(f"Final score: {score}")Output
Final score: 15Same result. But no global. And the function is pure. It takes input. It gives output. It does not mess with anything outside.
That is cleaner. And easier to test.
So let’s try to avoid global. Use return values instead.
Common Mistakes with Python Scope
Mistake 1: Trying to Use a Local Variable Outside the Function
def my_function(): x = 10
my_function()print(x) # Error!x is local. It does not exist outside the function.
So what do we do? We use it inside the function, or return it.
Mistake 2: Thinking We Can Change a Global Without global
x = 10
def my_function(): x = 20 # This creates a local x, does not change global
my_function()print(x) # 10So what do we do? We use global if we really need to change it.
def my_function(): global x x = 20Mistake 3: Using global Too Much
If we find ourselves using global everywhere, our code is probably not well organized. Let’s try returning values instead.
Mistake 4: Forgetting nonlocal in Nested Functions
def outer(): x = 10
def inner(): x = 20 # Creates a new local x, does not change outer x
inner() print(x) # 10So what do we do? We use nonlocal.
def inner(): nonlocal x x = 20Next, we will learn about Recursion in Python and see how a function can call itself.