Bucket 2 of 5 Name and attribute errors (4)
The parser passed, the code ran, then a lookup failed at runtime. Cause is almost always a
typo, a scope mistake, or a method called on a value that is the wrong type.
NameError: name is not defined
NameError: name 'data' is not defined
The interpreter reached the identifier and found no binding in the local, enclosing, global, or built-in scope. Causes: typo, wrong case, variable assigned inside a different function, import missing.
Broken def summary():
print(Data) # capital D, but the variable is lowercase
data = [10, 20, 30]
summary()
Fixed def summary(numbers): # take the binding as an argument instead
print(numbers)
data = [10, 20, 30]
summary(data)
Prevention. Pass data into functions through parameters, not through implicit module-level lookups. Treat capitalization as load-bearing.
UnboundLocalError: local variable referenced before assignment
UnboundLocalError: local variable 'count' referenced before assignment
Python decided the name is local because the function assigns to it somewhere, then the first use comes before the assignment. The global value is shadowed but not yet bound.
Broken count = 0
def bump():
count = count + 1 # right-hand count is local and unbound
return count
print(bump())
Fixed count = 0
def bump():
global count # declare the binding explicitly
count = count + 1
return count
print(bump())
Prevention. Prefer explicit arguments and returns over global mutation. When global state is required, declare it with global or nonlocal at the top of the function.
AttributeError: object has no attribute
AttributeError: 'NoneType' object has no attribute 'split'
You called a method on an object that does not have that method. NoneType is the most frequent culprit: a function returned None and the next line called something on the result.
Broken def first_word(s):
if not s:
return # implicit None
text = first_word("")
print(text.split()) # NoneType crash
Fixed def first_word(s):
if not s:
return "" # return an empty string, same type as input
return s.split()[0]
text = first_word("")
print(text.split() if text else [])
Prevention. Return a value of the same type the caller expects. Add an explicit None-check at every boundary where None could enter.
ImportError: cannot import name (circular import)
ImportError: cannot import name 'User' from partially initialized module 'models'
Two modules import each other at top level. When the first module starts importing the second, the second tries to read names from the first that are not bound yet.
Broken # models.py
from services import audit_user
class User:
pass
# services.py
from models import User
def audit_user(u: User):
return u
Fixed # services.py with a deferred import inside the function
from __future__ import annotations
def audit_user(u: "User"):
from models import User # imported on call, not at module load
assert isinstance(u, User)
return u
Prevention. Push imports that only types need into TYPE_CHECKING blocks or function bodies. Restructure modules so dependency arrows point one way.