The "Leaky Loop": Why Python doesn't have Block Scope.
Timothy sat back, staring at his monitor with a look of genuine confusion.
"That's impossible," he muttered. "I deleted that variable."
Margaret looked up from her paperwork. She stood and walked over to his desk. "Show me."
"I'm writing a script to process user accounts," Timothy explained. "I have a loop that searches for a specific admin user. Once the loop is finished, I want to ensure the temporary variable I used—current_user—is gone, so I don't accidentally use it later."
He pointed to the code.
# Timothy's Scope Test
admins = ["Alice", "Bob", "Charlie"]
print("Starting search...")
# The loop target variable is 'current_user'
for current_user in admins:
if current_user == "Bob":
print("Found Bob!")
print("Search complete.")
# Timothy expects 'current_user' to be undefined now
# because the loop is over.
print(f"The last user variable is: {current_user}")
"In most languages," Timothy said, "the variable current_user would only exist inside the for loop. Once the loop finishes, it should vanish. Attempting to print it should throw an error."
He hit Run.
Starting search...
Found Bob!
Search complete.
The last user variable is: Charlie
Timothy pointed at the screen. "It printed 'Charlie'. The variable is still alive. It leaked out of the loop and survived."
The Missing Block Scope
Margaret nodded. "You are assuming Python has Block Scope. It does not."
She pulled a chair over and opened a blank editor window to explain.
"In languages like C++ or Java," she said, "curly braces { } create a new scope. Variables defined inside them die when the brace closes. Python is different. Python has Function Scope, but not Block Scope."
She wrote the four letters of the law on the whiteboard: L E G B.
"Python resolves variables using the LEGB Rule," she explained. "When you ask for a variable name, Python searches these four scopes in order:"
- Local (Inside the current function)
- Enclosing (Inside any enclosing functions)
- Global (At the top level of the module)
-
Built-in (Python's pre-defined names like
printorlen)
"Notice the first letter?" Margaret asked. "Local means Function-Local. There is no 'Block' scope in this list."
"This means if statements, for loops, and while loops do not create a new scope," she continued. "They live inside the scope they are written in. The variable current_user didn't technically 'leak out' of the loop; the for statement simply assigned values to a variable in the current (Global) scope."
"So," Timothy realized, "when I wrote for current_user in admins, I wasn't creating a temporary loop variable. I was creating a Global variable that stays alive until the script ends."
"Correct," Margaret said. "And it holds the last value assigned to it—in this case, 'Charlie'."
The Function Barrier
"How do I stop the leak?" Timothy asked. "I want my variables to be temporary."
"You must create a real Local scope," Margaret said. "In Python, the primary way to create a new scope is to define a Function."
She wrapped his logic inside a simple function.
# Margaret's Fix: Functions contain scope
def find_admin():
admins = ["Alice", "Bob", "Charlie"]
# 'current_user' is now LOCAL to this function
for current_user in admins:
if current_user == "Bob":
print("Found Bob!")
find_admin()
# Now, if we try to access it globally...
try:
print(current_user)
except NameError as e:
print(f"Error: {e}")
Output:
Found Bob!
Error: name 'current_user' is not defined
"See?" Margaret said. "Because we put the loop inside find_admin(), the variable current_user became Local to that function. When the function finished, the Local scope was destroyed, and the variable vanished with it."
Margaret’s Cheat Sheet
Margaret opened her notebook to the "Scoping" section.
-
The Trap: Assuming
forloops orifblocks create a private scope. - The Rule: Python uses LEGB (Local, Enclosing, Global, Built-in).
-
The Consequence: Loop variables (
for i in range(10)) persist in the surrounding scope after the loop finishes. - The Fix:
-
Awareness: Know that
istill exists. - Functions: Wrap your code in a function to enforce true Local scope.
-
Cleanup: If you are in the global scope and really need it gone, use
del current_user.
Timothy looked at his original code. "I've been leaving 'trash' variables all over my global namespace, haven't I?"
"We all have," Margaret smiled. "Just remember: loops are open containers. Only functions put the lid on."
In the next episode, Margaret and Timothy will face "The Hidden Return"—where a missing return statement results in a value Timothy never expected.
Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.