UnboundLocalError - Biến toàn cục bỗng không tồn tại?
Hiện tượng lạ
Phần tiêu đề “Hiện tượng lạ”count = 0
def increment(): print(count) # Đọc biến toàn cục count += 1 # UnboundLocalError! ❌
increment()Error: UnboundLocalError: local variable 'count' referenced before assignment
What the Python?! Tại sao dòng đầu đọc được count nhưng dòng sau lại lỗi?! 😱
Giải thích
Phần tiêu đề “Giải thích”Python xác định scope LÚC COMPILE
Phần tiêu đề “Python xác định scope LÚC COMPILE”count = 0
def increment(): print(count) # Python thấy dòng dưới có 'count =' count += 1 # → Coi count là LOCAL variable # → Nhưng chưa được assign → UnboundLocalErrorPython scan toàn bộ function và thấy count = ... → coi count là local variable cho cả function!
Giải pháp: Khai báo global
Phần tiêu đề “Giải pháp: Khai báo global”count = 0
def increment(): global count # Khai báo count là global print(count) # OK count += 1 # OK ✅
increment()print(count) # 1Các trường hợp tương tự
Phần tiêu đề “Các trường hợp tương tự”Với list
Phần tiêu đề “Với list”# ❌ SAIitems = []
def add_item(item): items.append(item) # OK - Chỉ modify, không assign items = items + [item] # ❌ UnboundLocalError!
# ✅ ĐÚNGitems = []
def add_item(item): items.append(item) # ✅ Modify in-place OKVới nested scopes
Phần tiêu đề “Với nested scopes”def outer(): x = 0
def inner(): print(x) # OK - Đọc từ outer x += 1 # ❌ UnboundLocalError!
inner()
# ✅ ĐÚNG - Dùng nonlocaldef outer(): x = 0
def inner(): nonlocal x # Khai báo x từ outer scope print(x) x += 1 # ✅
inner() print(x) # 1global vs nonlocal
Phần tiêu đề “global vs nonlocal”global - Biến toàn cục
Phần tiêu đề “global - Biến toàn cục”x = 0
def modify(): global x # x ở global scope x = 10
modify()print(x) # 10nonlocal - Biến từ outer function
Phần tiêu đề “nonlocal - Biến từ outer function”def outer(): x = 0
def inner(): nonlocal x # x từ outer(), không phải global x = 10
inner() print(x) # 10Best Practices
Phần tiêu đề “Best Practices”✅ Tránh dùng global
Phần tiêu đề “✅ Tránh dùng global”# ❌ Tránhcount = 0
def increment(): global count count += 1
# ✅ Tốt hơn - Dùng classclass Counter: def __init__(self): self.count = 0
def increment(self): self.count += 1
counter = Counter()counter.increment()✅ Return giá trị mới
Phần tiêu đề “✅ Return giá trị mới”# ✅ Functional styledef increment(count): return count + 1
count = 0count = increment(count)Tóm tắt
Phần tiêu đề “Tóm tắt”UnboundLocalError xảy ra khi:
- ❌ Đọc biến trước khi assign trong cùng scope
- 🔧 Fix: Dùng
globalhoặcnonlocal- ✅ Better: Tránh dùng global, dùng return/class thay thế
Pattern:
# Globalglobal var_name
# Nonlocalnonlocal var_name