Python Variable Scope, Explained Like an Office Building
Imagine an office building. Each employee has a private desk where they keep their own notes, nobody outside that desk can see them. There's also a shared bulletin board in the lobby that everyone in the building can read and, with permission, write on. Python variables work the same way: some live privately inside a function, and some are shared across the whole program.
Local Scope: The Private Desk
A variable created inside a function only exists inside that function. Once the function finishes, the variable is gone, like notes on a desk that get cleared at the end of the day.
def take_notes(): note = "Buy milk" print(note) take_notes() # Buy milkprint(note) # NameError: note is not definednote never existed outside take_notes(). This is called local scope, and it's the default for anything defined inside a function.
Global Scope: The Lobby Bulletin Board
A variable created outside any function, at the top level of your script, is a global variable. Any function can read it, the same way any employee can walk by and read the lobby bulletin board.
company_name = "Acme Inc." def greet(): print(f"Welcome to {company_name}") greet()The Catch: You Can Read Globals, But Not Modify Them by Default
Reading the bulletin board is fine, but trying to scribble on it without permission can be problematic.
counter = 0 def increment(): counter += 1 # UnboundLocalError increment()Python assumes that if you assign to a variable inside a function, you're creating a new local variable, even if the global variable has the same name. To actually change a global variable, you must explicitly state so.
The global Keyword: Asking for Write Permission
counter = 0 def increment(): global counter counter += 1 increment()print(counter) # 1The global keyword tells Python "don't create a local copy, use the one from the lobby board."
Use this sparingly, functions that quietly change global state are harder to debug, the same way a building gets chaotic if everyone edits the shared board constantly.
Nested Functions and the nonlocal Keyword
Things get one level trickier with a function inside a function, think of it as a private meeting room inside someone's office. A variable in the outer function isn't local to the inner one, but it isn't global either.
def outer(): count = 0 def inner(): nonlocal count count += 1 inner() inner() print(count) # 2 outer()nonlocal tells Python "look one level up, not all the way to the global scope." Without it, inner() would create its own separate local count, and the outer one would never change.
The Scope Lookup Order (LEGB)
When Python looks up a variable name, it checks in this order:
- Local — inside the current function
- Enclosing — any outer function (relevant for nested functions)
- Global — the top level of the script
- Built-in — Python's own reserved names, like
lenorprint
This is often abbreviated as LEGB, and it's the exact order the office analogy follows: check your own desk first, then the meeting room, then the lobby board, then the building directory.
What's Next
Scope explains where a variable lives. The next tutorial in this series tackles recursion, what happens when a function calls itself, and why that isn't as strange as it sounds.
Python Functions 7-Part Masterclass:
- Part 1: Python Functions Explained Like a Recipe (Beginner's Guide)
- Part 2: Python Function Parameters and Arguments (Explained Like Ordering Food)
- Part 3: *args and **kwargs in Python Explained Like a Potluck Party
- Part 4: Python Lambda Functions Explained Like a Sticky Note
- Part 5: Python Variable Scope Explained Like an Office Building (Current)
- Part 6: Python Recursion Explained Like Russian Nesting Dolls
- Part 7: Python Closures and Decorators Explained Like Gift Wrapping