Python Scope of Variables

In the last lesson you learned Lambda Functions, small one-line functions you write on the spot. Now we look at something that quietly affects every function you write. When you make a variable inside a function, where does it actually live? Can the rest of your program see it? This is called scope. Getting it clear will save you from a whole class of confusing bugs.

πŸ€” Why Scope Matters

Picture a bigger program with many functions. One function uses a variable called total. Another function, written by someone else on your team, also uses a variable called total. If both total variables were shared across the whole program, they would step on each other. One function would change a value the other one was counting on. You would get wrong numbers and no clear reason why.

That is the pain scope solves. Scope is the part of your program where a variable can be seen and used. A variable made inside a function stays inside that function. So two functions can both use a name like total and never clash. Each one gets its own private copy.

🧩 Local and Global

There are two kinds of scope you meet first.

  • A local variable is made inside a function. It lives only inside that function. When the function finishes, it is gone.
  • A global variable is made outside every function, at the top level of your file. It can be read from anywhere, including inside functions.

Think of it like rooms in a house. A local variable is a note left on a desk inside one room. Only the person in that room can read it. A global variable is a note stuck on the front door, where everyone in the house walks past and can read it.

πŸ”’ A Local Variable Stays Inside

Let’s see a local variable in action. This function makes a variable called message and prints it.

def greet():
message = "Hello from inside"
print(message)
greet()

The variable message is made inside greet. So it is local to greet. When we call the function, it prints fine.

Output

Hello from inside

Now watch what happens if we try to use message outside the function. This is the part that surprises people.

def greet():
message = "Hello from inside"
print(message)
greet()
print(message) # trying to use it out here

Python runs the function, prints the greeting, then crashes on the last line.

Output

Hello from inside
Traceback (most recent call last):
File "main.py", line 6, in <module>
print(message)
^^^^^^^
NameError: name 'message' is not defined

Read that last line. NameError: name 'message' is not defined. Out here, message does not exist. It was born inside greet and it died when greet finished. That is exactly what local means. The variable simply is not visible outside its own function.

🌍 Reading a Global Inside a Function

Now the other direction. A variable made outside any function is global. A function is allowed to look out and read it.

Here app_name is made at the top level, so it is global. The function reads it.

app_name = "Photo Editor"
def show_title():
print("Welcome to", app_name)
show_title()

The function never made app_name itself. It just reached out and read the global one.

Output

Welcome to Photo Editor

So the rule is one-directional. A function can read a global variable. But a variable made inside a function cannot be seen from outside. Reading out is fine. Reaching in is not.

πŸ”Ž How Python Looks Up a Name

When you use a variable inside a function, Python searches in a set order. It checks the closest place first, then moves outward.

  • First it looks at the local names, the ones made inside this function.
  • If it does not find the name there, it looks at the global names, the ones made at the top of the file.
  • If it is still not found anywhere, you get that NameError.

This is why a local total never clashes with another function’s local total. Python finds the local one first and stops looking. Here is the short version of the two kinds.

Scope Where it is made Who can see it
Local Inside a function Only that function
Global At the top level of the file The whole file, including inside functions

✍️ Changing a Global With the global Keyword

Reading a global is easy. But what if a function tries to change one? This trips people up. Let’s look.

count = 0
def add_one():
count = count + 1 # this line fails
add_one()

You might expect count to become 1. Instead Python crashes.

Output

Traceback (most recent call last):
File "main.py", line 6, in <module>
add_one()
File "main.py", line 4, in add_one
count = count + 1
^^^^^
UnboundLocalError: cannot access local variable 'count' where it is not associated with a value

Here is what happened. The moment a function assigns to a name, Python treats that name as local to the function. So inside add_one, the count on the left is a brand new local variable. But the count on the right has no value yet. So Python complains.

If you really need the function to change the global one, you tell Python with the global keyword. It says β€œdo not make a new local, use the global one”.

count = 0
def add_one():
global count
count = count + 1
add_one()
add_one()
print(count)

The line global count tells the function to work on the global count, not a new local copy. Now each call really updates it.

Output

2

It works. But read the warning below, because you will rarely want to do this.

Caution

Changing globals from inside functions is usually a sign of trouble. When many functions all reach in and edit the same global, you lose track of who changed what, and bugs get hard to find. The cleaner habit is to pass values in as arguments and return the result back out. Reach for global only when you have a strong, specific reason.

πŸ§‘β€πŸ’» The Clean Way Instead

Here is the same counting idea written the recommended way. No global anywhere. The function takes a value in and hands a new value back.

def add_one(value):
return value + 1
count = 0
count = add_one(count)
count = add_one(count)
print(count)

Walk through it.

  • add_one takes value as an argument, so it works on whatever you pass in.
  • It returns value + 1, a fresh result, without touching anything outside.
  • Out at the top level, we update count ourselves by catching what the function returned.

Output

2

Same answer, 2. But now the function does not secretly change anything. You can read the code and see exactly where count gets updated. That clarity is why this style is preferred.

⚠️ Common Mistakes

A few scope traps catch people again and again. Watch for these.

  • Trying to use a local variable outside its function. It does not exist out there, so you get a NameError.
# ❌ Avoid: result is local to calc, invisible outside
def calc():
result = 5 * 5
calc()
print(result) # NameError
# βœ… Good: return it, then use it outside
def calc():
return 5 * 5
answer = calc()
print(answer)
  • Assigning to a global inside a function without global, then being surprised by UnboundLocalError. The moment you assign, Python makes it local.
  • Reaching for global as a quick fix. It often hides the real design problem. Pass values in and return them out instead.
# ❌ Avoid: function quietly edits a global
total = 0
def add(x):
global total
total = total + x
# βœ… Good: function returns, caller updates
def add(total, x):
return total + x
total = 0
total = add(total, 5)

βœ… Best Practices

Keep these habits and scope stays simple.

  • Keep variables local by default. Make them inside the function that uses them.
  • Pass data into a function with arguments, and send results back with return. This keeps each function self-contained.
  • Treat global variables mostly as read-only settings, like an app name or a fixed limit.
  • Avoid the global keyword unless you have a clear, specific reason. There is almost always a cleaner way.
  • If two functions need to share and update the same value, return it and pass it along, rather than reaching into a global.

🧩 What You’ve Learned

βœ… Scope is the part of your program where a variable can be seen and used.

βœ… A local variable is made inside a function and exists only there. Using it outside gives a NameError.

βœ… A global variable is made at the top level and can be read from inside functions.

βœ… Python looks for a name locally first, then globally, and raises a NameError if it finds it nowhere.

βœ… The global keyword lets a function change a global, but passing values in and returning them out is the cleaner habit.

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    Where can a local variable be used?

    Why: A local variable is created inside a function and lives only there. Outside that function it does not exist.

  2. 2

    What happens if you print a local variable from outside its function?

    Why: The variable does not exist outside its function, so Python cannot find the name and raises a NameError.

  3. 3

    Can a function read a global variable that was made at the top of the file?

    Why: Reading is allowed. A function can look outward and read a global variable without any special keyword.

  4. 4

    What does the global keyword do inside a function?

    Why: Without global, assigning a name makes it local. The global keyword tells Python to use and change the global variable instead.

πŸš€ What’s Next?

You now know where your variables live and why keeping them local keeps your code clean. Next we look at a function that calls itself to solve a problem one small piece at a time.

Recursion in Python

Share & Connect