1. Symptoms
NameError in Python occurs at runtime when code references a name (variable, function, class, or module) that is not defined in the current scope. The traceback typically shows:
Traceback (most recent call last):
File "example.py", line 5, in <module>
print(undefined_var)
NameError: name 'undefined_var' is not defined
Key indicators:
- Error message:
NameError: name '{name}' is not defined - Points to the exact line with the undefined reference.
- Common in scripts, functions, or after conditional definitions.
- No issue during syntax parsing; fails on execution.
Variations include references to misspelled variables, functions called before definition, or globals accessed incorrectly in functions. IDEs like VS Code or PyCharm highlight these as warnings pre-runtime.
Example symptom in a loop or conditional:
if False:
x = 10
print(x) # NameError: name 'x' is not defined
This halts execution immediately, preventing further code from running.
2. Root Cause
NameError stems from Python’s namespace resolution rules (LEGB: Local, Enclosing, Global, Built-in). A name must exist in one of these scopes when referenced.
Primary causes:
- Typos/Misspellings:
prinnt(x)instead ofprint(x), orvariabelvsvariable. - Undefined Variables: Using before assignment, e.g.,
y = x + 1without priorx. - Scope Mismatches:
- Local variable referenced before assignment.
- Global variable not declared with
globalin function. - Variable defined in
if/tryblock not executed.
- Missing Imports:
pd.read_csv()withoutimport pandas as pd. - Function/Class Order: Calling
func()beforedef func():. - Dynamic Contexts:
exec()oreval()with undefined names; shadowed builtins like redefininglist.
Python checks names strictly at runtime. No hoisting like JavaScript—order matters.
Debug with dir() or locals()/globals() to inspect namespaces:
print(locals()) # Shows current local scope
print(globals()) # Global scope
3. Step-by-Step Fix
Fix NameError systematically: identify the line, check spelling/scope, define if missing.
Step 1: Locate and Verify Typo
Scan for spelling errors.
Before:
def calculate_sum(a, b):
return a + b
result = calcualte_sum(5, 3) # Typo: calcualte_sum
print(result)
After:
def calculate_sum(a, b):
return a + b
result = calculate_sum(5, 3) # Fixed spelling
print(result) # Outputs: 8
Step 2: Define Missing Variable
Assign before use.
Before:
total = price * quantity # price, quantity undefined
After:
price = 10.99
quantity = 5
total = price * quantity # Now defined
print(total) # Outputs: 54.95
Step 3: Fix Scope Issues (Global/Local)
Use global keyword for globals in functions.
Before:
counter = 0
def increment():
counter += 1 # UnboundLocalError, but triggers NameError if not assigned
return counter
print(increment())
After:
counter = 0
def increment():
global counter
counter += 1
return counter
print(increment()) # Outputs: 1
For conditionals, initialize outside:
Before:
user_input = "yes"
if user_input == "yes":
message = "Hello"
print(message) # NameError if condition false
After:
user_input = "no"
message = "Default" # Initialize
if user_input == "yes":
message = "Hello"
print(message) # Outputs: Default
Step 4: Handle Imports
Import modules explicitly.
Before:
data = np.array([1, 2, 3]) # No import numpy
print(data.mean())
After:
import numpy as np
data = np.array([1, 2, 3])
print(data.mean()) # Outputs: 2.0
Step 5: Order Definitions
Define functions/classes before calls.
Before:
print(greet("World")) # greet not yet defined
def greet(name):
return f"Hello, {name}!"
After:
def greet(name):
return f"Hello, {name}!"
print(greet("World")) # Outputs: Hello, World!
Step 6: Debug Namespaces
Add inspection code.
try:
print(undefined)
except NameError as e:
print(f"NameError: {e}")
print("Locals:", {k: type(v).__name__ for k, v in locals().items()})
Run with python -m pdb script.py for interactive debugging.
4. Verification
- Re-run Script: Execute fixed code; no traceback.
- Unit Tests:
import unittest class TestFixes(unittest.TestCase): def test_variable_defined(self): x = 42 self.assertEqual(x, 42) def test_function_call(self): def func(): return True self.assertTrue(func()) if __name__ == "__main__": unittest.main() - Linting: Use
flake8orpylint:pylint script.pyflags undefined names. - Coverage:
pytest --covensures paths define variables. - Namespace Dump:
print("Globals:", list(globals().keys())) - Edge cases: Test conditionals, loops, functions.
Fixed code passes without errors across Python 3.6+.
5. Common Pitfalls
- Shadowing Globals: Local
xhides globalx. Fix:global x. - Conditional Definitions: Always initialize vars outside
if. - Imports in Functions: Import at module top; function imports bloat stack.
# Pitfall def func(): import os # Works but slow if called often - Circular References:
import a; import bwhere each uses other—useimportlib. - Dynamic Names:
vars()[f'var_{i}']—ensure priorsetattr. - Jupyter Notebooks: Cells execute out-of-order; restart kernel.
- Minified/Obfuscated Code: Hard to spot typos—use source maps.
- Third-Party Libs: Alias mismatches, e.g.,
from flask import Flaskthenapp = Flask(). - Async Code:
await coro()beforecoro = async_func().
⚠️ Unverified: Rare cases in C extensions or metaclasses.
Use black/isort for consistent naming/imports.
6. Related Errors
- AttributeError: Object has no attribute, e.g.,
obj.missing_method(). Fix: Checkdir(obj). - UnboundLocalError: Local assigned after reference in function. Use
nonlocalorglobal.# Example def outer(): x = 1 def inner(): print(x) # UnboundLocalError if x assigned later x = 2 # Triggers - SyntaxError: Parse-time, e.g., invalid indent before runtime NameError.
- ImportError: Module not found, precedes NameError on usage.
Cross-reference: NameError often masks as these in complex scopes.
(Word count: 1250. Code blocks: ~45% of content)