
Bạn vừa hào hứng nhấn “Run” cho đoạn code Python của mình và nhận lại một thông báo lạnh lùng:
NameError: name 'total' is not defined
Hoặc có thể là:
NameError: name 'DataFrame' is not defined
Cảm giác đầu tiên thường là sự bối rối, thậm chí là hơi “cay cú”: “Vô lý! Rõ ràng mình đã khai báo biến total ở trên rồi mà? Sao Python lại bảo không tồn tại?”
Bạn xem thêm:
- Cách Quản Lý Công Nợ Phải Thu, Phải Trả Bằng Excel Tự Động
- TypeError: unsupported operand type(s) for +: ‘int’ and ‘str’ là gì?
- Quy Trình 5 Bước Lập Báo Cáo Tài Chính Trên Excel Tự Động Chuẩn Mực
Nếu bạn từng trải qua cảm giác này, bạn không hề đơn độc. NameError là một trong những lỗi phổ biến nhất, “chào đón” hầu hết mọi người khi mới bắt đầu học Python, và đôi khi vẫn quay lại ám ảnh cả những lập trình viên kinh nghiệm.
Thực ra, Python không hề vô lý. Nó chỉ đang nói một sự thật rất thẳng thắn:
“Tại thời điểm này, trong phạm vi tôi đang nhìn, tôi không biết total là ai cả. Bạn chưa giới thiệu nó cho tôi.”
Lỗi này không phải là dấu chấm hết, mà là một lời nhắc nhở về cách Python quản lý các tên gọi (biến, hàm, class). Trong bài viết chuyên sâu này, chúng ta sẽ cùng nhau mổ xẻ NameError từ gốc rễ:
1. Giải mã NameError: Hiểu tận gốc lỗi này là gì

Khi bạn viết x = 10 trong Python, bạn đang thực hiện hai việc:
-
Tạo ra một đối tượng (object) có giá trị là
10. -
Gán một cái tên (name) là
xđể tham chiếu đến đối tượng đó.
NameError xảy ra khi Python cố gắng tìm một cái tên theo yêu cầu của bạn, nhưng không thể tìm thấy nó trong bất kỳ “danh bạ” nào mà nó biết.
Thông báo lỗi đầy đủ thường trông như thế này:
NameError: name 'xxx' is not defined
Trong đó:
-
NameError: Loại lỗi liên quan đến việc tra cứu tên.
-
name ‘xxx’: Tên cụ thể mà Python không tìm thấy.
-
is not defined: Chưa được định nghĩa hoặc không tồn tại trong phạm vi hiện tại.
1.1. Namespace (Không gian tên) là gì?
Để hiểu NameError, bạn cần hiểu về Namespace. Hãy tưởng tượng Namespace giống như một cuốn danh bạ (dictionary) mà Python sử dụng để quản lý tất cả các tên gọi.
-
Key: Là tên của biến, hàm, class (ví dụ:
x,calculate_total,User). -
Value: Là tham chiếu đến đối tượng mà tên đó trỏ tới.
Khi bạn gọi print(x), Python sẽ lục trong Namespace hiện tại để tìm key x. Nếu tìm thấy, nó lấy giá trị tương ứng. Nếu không, nó sẽ tìm ở các Namespace cấp cao hơn. Nếu tìm hết mọi nơi mà vẫn không thấy, NameError sẽ được ném ra.
1.2. Các loại Namespace
Python có nhiều loại Namespace, được tạo ra tại các thời điểm khác nhau:
-
Built-in Namespace: Chứa các hàm và hằng số có sẵn của Python (như
print(),len(),True). Nó được tạo khi Python khởi động và tồn tại mãi mãi. -
Global Namespace: Chứa các tên được định nghĩa ở cấp cao nhất của một module hoặc file script. Nó được tạo khi module được import hoặc script bắt đầu chạy.
-
Local Namespace: Chứa các tên được định nghĩa bên trong một hàm. Nó được tạo khi hàm được gọi và bị xóa đi khi hàm kết thúc (trừ trường hợp đặc biệt như closures).
Hiểu về Namespace là bước đầu tiên. Bước tiếp theo là hiểu cách Python quyết định nơi để tìm kiếm các tên gọi đó.
2. Tại sao Scope là chìa khóa

Scope (Phạm vi) là khu vực trong chương trình mà tại đó một Namespace có thể được truy cập trực tiếp. Nói cách khác, Scope xác định “tầm nhìn” của một biến.
Rất nhiều NameError xảy ra không phải vì biến chưa được tạo, mà vì nó được tạo ở một Scope khác mà đoạn code hiện tại không thể “nhìn thấy”.
2.1. Quy tắc LEGB: Thứ tự tra cứu tên trong Python
Python tuân thủ một quy tắc nghiêm ngặt khi tìm kiếm một tên gọi, được gọi là quy tắc LEGB:
-
L (Local): Tìm kiếm đầu tiên trong phạm vi cục bộ (bên trong hàm hiện tại).
-
E (Enclosing): Nếu không tìm thấy ở Local, nó tìm kiếm trong phạm vi bao đóng (nếu hàm hiện tại nằm trong một hàm khác).
-
G (Global): Nếu vẫn không thấy, nó tìm kiếm trong phạm vi toàn cục (cấp độ module/file).
-
B (Built-in): Cuối cùng, nó tìm kiếm trong phạm vi có sẵn của Python.
Nếu Python đi hết 4 bước này mà vẫn không tìm thấy tên, nó sẽ dừng lại và ném ra NameError.
2.2. Minh họa quy tắc LEGB
Hãy xem xét ví dụ sau để hiểu rõ hơn:
# G (Global): Biến 'x' ở phạm vi toàn cục
x = "Global X"
def outer_function():
# E (Enclosing): Biến 'x' ở phạm vi bao đóng đối với inner_function
x = "Enclosing X"
def inner_function():
# L (Local): Biến 'x' ở phạm vi cục bộ
x = "Local X"
print(x)
inner_function()
outer_function()
# Output: Local X
Trong ví dụ này:
-
Khi
inner_functiongọiprint(x), Python tìm trong Local trước. Nó thấyx = "Local X", nên nó dùng giá trị này và dừng tìm kiếm.
Bây giờ, hãy thử xóa biến Local:
x = "Global X"
def outer_function():
x = "Enclosing X"
def inner_function():
# Không có x ở Local nữa
print(x)
inner_function()
outer_function()
# Output: Enclosing X
Lần này, Python không tìm thấy x ở Local. Nó chuyển sang Enclosing (phạm vi của outer_function). Nó thấy x = "Enclosing X" và sử dụng nó.
Hiểu rõ LEGB là chìa khóa quan trọng nhất để giải quyết các vấn đề liên quan đến NameError và Scope.
3. 10 Tình huống kinh điển gây NameError và Cách khắc phục triệt để

Bây giờ chúng ta đã hiểu cơ chế bên dưới, hãy đi sâu vào các tình huống thực tế gây ra NameError và các giải pháp tương ứng.
3.1. Sai thứ tự: Dùng trước khi khai báo
Python là ngôn ngữ thông dịch (interpreted language) và thực thi mã tuần tự từ trên xuống dưới. Điều này có nghĩa là một tên phải được định nghĩa trước khi nó được sử dụng.
Ví dụ lỗi:
print("Tổng số tiền là:", total_amount) # Lỗi ở đây
# Mãi đến đây mới khai báo
total_amount = 100 + 50
Python nghĩ gì: Khi chạy dòng print, Python nhìn vào Namespace hiện tại. Tên total_amount chưa hề xuất hiện vì dòng code định nghĩa nó nằm ở dưới.
Lỗi:
NameError: name 'total_amount' is not defined
Cách sửa: Luôn đảm bảo thứ tự khai báo trước khi sử dụng.
total_amount = 100 + 50
print("Tổng số tiền là:", total_amount)
3.2. “Thảm họa” Typo: Gõ sai chính tả và Case Sensitivity
Đây là nguyên nhân phổ biến đến mức đáng ngạc nhiên. Python phân biệt chữ hoa và chữ thường (Case Sensitive).
Ví dụ lỗi 1 (Sai chính tả):
customer_address = "123 Main St"
print(custmer_adress) # Thiếu 'o' và 'd'
Ví dụ lỗi 2 (Case Sensitivity):
API_KEY = "secret_token"
print(api_key) # Viết thường thay vì viết hoa
Python nghĩ gì: Python không cố gắng “đoán” ý định của bạn. API_KEY và api_key là hai thực thể riêng biệt trong mắt nó.
Cách sửa và Phòng ngừa:
-
Kiểm tra kỹ: Khi gặp
NameError, hãy so sánh từng ký tự giữa tên trong thông báo lỗi và tên bạn đã khai báo. -
Nhất quán Convention: Tuân thủ chặt chẽ PEP 8 (ví dụ:
snake_casecho biến và hàm). -
Tận dụng IDE: Sử dụng tính năng Auto-complete (tự động hoàn thành) của IDE (VS Code, PyCharm) để tránh gõ sai.
3.3. Quên dấu nháy kép: Khi String bị nhầm thành Biến (Rất quan trọng!)

Đây là một lỗi cực kỳ phổ biến với người mới bắt đầu, khi họ chưa phân biệt rõ giữa dữ liệu kiểu chuỗi (string literal) và tên biến.
Ví dụ lỗi:
def set_status(new_status):
print(f"Trạng thái mới: {new_status}")
set_status(active) # Quên dấu nháy kép cho chuỗi "active"
Python nghĩ gì: Khi thấy active không có dấu nháy (" hoặc '), Python coi đó là một tên biến. Nó bắt đầu quá trình tra cứu LEGB để tìm xem biến active đã được định nghĩa ở đâu chưa. Vì chưa có biến nào tên active tồn tại, nó ném ra lỗi.
Lỗi:
NameError: name 'active' is not defined
Cách sửa: Luôn nhớ sử dụng dấu nháy kép hoặc nháy đơn cho các giá trị chuỗi.
set_status("active")
3.4. Biến Local bị dùng ở Global (Lỗi Scope phổ biến nhất)
Đây là tình huống gây bối rối nhất cho nhiều người. Bạn khai báo biến bên trong một hàm, nhưng lại cố gắng truy cập nó từ bên ngoài hàm đó.
Ví dụ lỗi:
def calculate_tax(price):
tax_rate = 0.1
final_tax = price * tax_rate
return final_tax
calculate_tax(100)
print(final_tax) # Cố gắng truy cập biến local từ scope global
Python nghĩ gì: Biến final_tax thuộc về Local Namespace của hàm calculate_tax. Khi hàm chạy xong, Local Namespace này bị xóa. Ở phạm vi Global (nơi câu lệnh print đang chạy), final_tax không tồn tại.
Lỗi:
NameError: name 'final_tax' is not defined
Cách sửa đúng đắn: Hàm nên giao tiếp với thế giới bên ngoài thông qua giá trị trả về (return value).
def calculate_tax(price):
tax_rate = 0.1
final_tax = price * tax_rate
return final_tax
# Sử dụng giá trị trả về của hàm
tax_amount = calculate_tax(100)
print(tax_amount)
3.5. Biến Global và “Cạm bẫy” UnboundLocalError

Ngược lại, điều gì xảy ra khi bạn muốn thay đổi một biến Global từ bên trong một hàm?
Ví dụ lỗi:
count = 0 # Biến Global
def increment():
# Cố gắng thay đổi biến Global
count = count + 1
print(f"Count inside function: {count}")
increment()
Python nghĩ gì: Đây là một điểm tinh tế của Python. Khi Python thấy một phép gán (count = ...) bên trong một hàm, nó mặc định coi count là một biến Local.
Tuy nhiên, ở vế phải của phép gán (count + 1), bạn lại đang cố gắng truy cập giá trị của count. Vì count đã bị đánh dấu là Local, nhưng lại chưa được gán giá trị trong hàm trước khi sử dụng, Python sẽ bối rối.
Lỗi:
UnboundLocalError: local variable 'count' referenced before assignment
Mặc dù đây là UnboundLocalError, bản chất vẫn là vấn đề về tra cứu tên và scope.
Cách sửa 1 (Khuyến khích): Tránh dùng biến Global
Thiết kế lại hàm để nhận giá trị và trả về giá trị mới.
def increment(current_count):
return current_count + 1
count = 0
count = increment(count)
Cách sửa 2 (Ít khuyến khích): Sử dụng từ khóa global
Nếu bạn thực sự cần thay đổi trạng thái toàn cục, bạn phải khai báo rõ ràng ý định của mình bằng từ khóa global.
count = 0
def increment():
global count # Khai báo rõ: Tôi muốn dùng biến 'count' ở Global scope
count = count + 1
increment()
3.6. Lỗi trong Nested Functions và vai trò của nonlocal

Tương tự như vấn đề Global/Local, chúng ta có vấn đề Enclosing/Local khi làm việc với các hàm lồng nhau (nested functions).
Ví dụ lỗi (Tương tự UnboundLocalError):
def counter():
num = 0 # Biến ở Enclosing scope
def incrementer():
# Cố gắng thay đổi biến ở Enclosing scope
num = num + 1
return num
return incrementer
c = counter()
c()
Python nghĩ gì: Giống như trường hợp trên, num bị coi là Local trong incrementer do có phép gán, dẫn đến UnboundLocalError.
Cách sửa: Sử dụng từ khóa nonlocal
Để thay đổi biến ở phạm vi Enclosing (không phải Global), Python cung cấp từ khóa nonlocal.
def counter():
num = 0
def incrementer():
nonlocal num # Khai báo rõ: Tôi muốn dùng 'num' ở Enclosing scope gần nhất
num = num + 1
return num
return incrementer
c = counter()
print(c()) # Output: 1
3.7. Import “nửa vời” hoặc sai cách

Khi làm việc với các thư viện hoặc module khác, bạn phải import chúng vào Namespace hiện tại trước khi sử dụng.
Ví dụ lỗi 1 (Quên import):
# Quên import thư viện math
result = math.sqrt(16)
Lỗi:
NameError: name 'math' is not defined
Ví dụ lỗi 2 (Import sai cách):
from math import sqrt
# Đã import sqrt trực tiếp, nhưng lại gọi qua tên module 'math'
result = math.sqrt(16)
Python nghĩ gì: Trong ví dụ 2, bạn chỉ yêu cầu Python mang tên sqrt vào Namespace hiện tại. Tên math (module) không hề được import vào. Do đó, math không tồn tại.
Lỗi:
NameError: name 'math' is not defined
Cách sửa:
-
Import module:
import math result = math.sqrt(16) -
Import đối tượng cụ thể:
from math import sqrt result = sqrt(16)
3.8. Đặc thù của Class: Quên self khi truy cập thuộc tính
Trong lập trình hướng đối tượng (OOP) với Python, việc quản lý tên trong phạm vi của Class cũng có thể gây ra NameError.
Ví dụ lỗi:
class Dog:
def __init__(self, name):
self.name = name # Instance attribute
def bark(self):
# Lỗi: Quên 'self.' khi truy cập instance attribute
print(f"{name} says Woof!")
Python nghĩ gì: Bên trong phương thức bark(), khi thấy name, Python bắt đầu tìm kiếm LEGB. Nó tìm trong Local scope của bark(). Nó không tự động tìm trong các thuộc tính của instance (self).
Lỗi:
NameError: name 'name' is not defined
Cách sửa: Luôn sử dụng self. để truy cập các thuộc tính hoặc phương thức của instance.
def bark(self):
print(f"{self.name} says Woof!")
3.9. Jupyter Notebook/Google Colab: Khi thứ tự Cell gây hỗn loạn

Môi trường tương tác như Jupyter Notebook cho phép bạn chạy các cell (ô mã) không theo thứ tự từ trên xuống dưới. Trạng thái của Namespace được duy trì giữa các lần chạy cell.
Kịch bản gây lỗi:
-
Cell 1:
data = [1, 2, 3] -
Cell 2:
print(sum(data))
Bạn mở Notebook, Restart Kernel (khởi động lại môi trường thực thi), và chỉ chạy Cell 2 mà quên chạy Cell 1 trước đó.
Lỗi:
NameError: name 'data' is not defined
Python nghĩ gì: Khi Kernel được restart, mọi Namespace (trừ Built-in) đều bị xóa. Khi Cell 2 chạy, biến data chưa hề được tạo ra trong phiên làm việc mới này.
Cách phòng ngừa trong Jupyter:
-
Run All: Thường xuyên sử dụng chức năng “Run All” hoặc “Run All Above” để đảm bảo code chạy đúng thứ tự từ trên xuống dưới.
-
Kiểm tra lại sau khi Restart: Sau khi Restart Kernel, luôn chạy lại từ đầu để đảm bảo tính nhất quán.
3.10. Khởi tạo biến trong điều kiện (If/Try)
Một cái bẫy tinh vi khác là khi biến chỉ được khởi tạo trong một nhánh điều kiện nhất định, nhưng luồng thực thi lại không đi vào nhánh đó.
Ví dụ lỗi:
user_age = 15
if user_age >= 18:
access_level = "Adult"
# Lỗi xảy ra ở đây nếu user_age < 18
print(f"Access level: {access_level}")
Python nghĩ gì: Vì user_age là 15, điều kiện if sai. Dòng code access_level = "Adult" không bao giờ được thực thi. Khi đến dòng print, biến access_level chưa tồn tại trong Namespace.
Lỗi:
NameError: name 'access_level' is not defined
Cách sửa: Luôn đảm bảo biến được khởi tạo trong mọi trường hợp, hoặc có giá trị mặc định.
user_age = 15
access_level = "Restricted" # Giá trị mặc định
if user_age >= 18:
access_level = "Adult"
print(f"Access level: {access_level}")
Hoặc sử dụng cấu trúc if...else đầy đủ.
4. Kỹ thuật Debug NameError chuyên nghiệp

Khi gặp NameError, thay vì sửa mò, hãy áp dụng các kỹ thuật debug có hệ thống để tìm ra nguyên nhân nhanh chóng.
4.1. Đọc và Phân tích Stack Trace (Truy vết lỗi)
Stack Trace (hay Traceback) là người bạn tốt nhất của bạn khi debug. Đừng chỉ đọc dòng cuối cùng.
Traceback (most recent call last):
File "app.py", line 15, in <module>
process_data()
File "app.py", line 10, in process_data
print(result)
NameError: name 'result' is not defined
Cách đọc (từ dưới lên):
-
Dòng cuối cùng: Cho biết loại lỗi (
NameError) và tên cụ thể (result). -
Các dòng phía trên: Cho biết chính xác vị trí lỗi xảy ra (File
app.py, line 10, bên trong hàmprocess_data). Nó cũng cho thấy luồng thực thi dẫn đến lỗi.
Với thông tin này, bạn biết chính xác cần phải nhìn vào đâu: hàm process_data ở dòng 10.
4.2. Kiểm tra Scope và Chính tả
Khi đã xác định được vị trí lỗi (print(result)), hãy tự hỏi:
-
Chính tả: Tên
resultcó đúng không? Hay nó phải làresultshayfinal_result? -
Scope: Biến
resultđược định nghĩa ở đâu? Nó có phải là biến Local không? Nó đã được gán giá trị trước dòng 10 chưa? Nó có nằm trong khốiifnào không?
4.3. Kiểm tra Namespace: Dùng globals(), locals()
Python cung cấp các hàm hữu ích để “soi” vào Namespace hiện tại.
-
locals(): Trả về một dictionary chứa tất cả các biến Local và giá trị của chúng. -
globals(): Trả về một dictionary chứa tất cả các biến Global.
Ví dụ debug:
def process_data():
data = [1, 2, 3]
final_result = sum(data)
print("--- Debug Info: locals() ---")
print(locals())
print("----------------------------")
print(result) # Dòng gây lỗi
Output Debug:
--- Debug Info: locals() ---
{'data': [1, 2, 3], 'final_result': 6}
----------------------------
NameError: name 'result' is not defined
Nhìn vào output của locals(), bạn thấy rõ ràng không có biến nào tên result, chỉ có final_result. Điều này xác nhận ngay lập tức đây là lỗi typo hoặc dùng sai tên biến.
4.4. Sử dụng Debugger (IDE/PDB)
Đối với các lỗi phức tạp hơn, sử dụng Debugger là cách hiệu quả nhất. Các IDE như VS Code hay PyCharm có công cụ Debugger mạnh mẽ.
Bạn có thể đặt Breakpoint (điểm dừng) ngay trước dòng gây lỗi. Khi chương trình tạm dừng tại đó, bạn có thể kiểm tra giá trị của tất cả các biến trong các scope khác nhau (Local, Global) tại thời điểm đó. Điều này giúp bạn hiểu chính xác trạng thái của chương trình trước khi lỗi xảy ra.
5. Phòng bệnh hơn chữa bệnh

Mục tiêu cuối cùng không chỉ là sửa NameError khi nó xảy ra, mà là viết code sao cho nó hiếm khi xuất hiện.
5.1. Quy tắc đặt tên nhất quán và rõ ràng (PEP 8)
Việc tuân thủ một convention đặt tên giúp giảm thiểu lỗi typo và làm cho code dễ đọc hơn. PEP 8 là tiêu chuẩn vàng trong cộng đồng Python:
-
snake_casecho biến và hàm (ví dụ:user_count). -
PascalCasecho Class (ví dụ:UserProfile). -
UPPER_SNAKE_CASEcho hằng số (ví dụ:MAX_RETRIES).
Tránh các tên viết tắt mơ hồ (cnt, res) và ưu tiên các tên mô tả rõ ràng (count, result).
5.2. Sử dụng Công cụ hỗ trợ hiện đại: Linters và Type Hinting
Đừng chỉ dựa vào trình thông dịch Python để bắt lỗi. Hãy sử dụng các công cụ phân tích mã tĩnh.
-
Linters (Flake8, Pylint): Các công cụ này quét code của bạn để tìm các lỗi tiềm ẩn, bao gồm cả việc sử dụng các biến chưa được định nghĩa. Tích hợp Linter vào IDE sẽ giúp bạn phát hiện
NameErrorngay khi bạn gõ code. -
Type Hinting và MyPy: Python 3.5+ hỗ trợ Type Hinting. Sử dụng công cụ như MyPy để kiểm tra kiểu tĩnh có thể giúp phát hiện nhiều lỗi, bao gồm cả
NameErrordo typo, trước khi bạn chạy code.
def greet(name: str) -> None:
print(f"Hello, {nmae}") # MyPy và Linter sẽ báo lỗi ở đây ngay lập tức (do typo nmae)
5.3. Ưu tiên Hàm “Thuần khiết” và Giảm Global State
NameError thường phức tạp hơn trong các chương trình phụ thuộc nhiều vào biến Global. Hãy cố gắng viết các hàm “thuần khiết” (Pure Functions) nếu có thể:
-
Hàm chỉ sử dụng dữ liệu được truyền vào qua tham số.
-
Hàm trả về kết quả mà không thay đổi biến Global.
Điều này làm cho code dễ kiểm tra, dễ debug và ít khả năng gặp lỗi về scope.
5.4. Tổ chức Code mạch lạc và Thứ tự rõ ràng
Cấu trúc project của bạn sao cho luồng thực thi luôn rõ ràng.
-
Đặt các câu lệnh import ở đầu file.
-
Định nghĩa hằng số và các hàm.
-
Cuối cùng là logic chính, thường được đặt trong một hàm
main()và được gọi trong khốiif __name__ == "__main__":.
Cấu trúc này đảm bảo rằng mọi thứ đều đã được định nghĩa khi khối main được thực thi.
6. Kết luận và FAQ

Lỗi NameError: name 'x' is not defined là một phần không thể thiếu trong hành trình học Python. Thay vì xem nó như một sự cản trở, hãy coi đó là cơ hội để hiểu sâu hơn về cách Python hoạt động, đặc biệt là về Namespace và Scope (quy tắc LEGB).
Tóm lại, khi gặp NameError, hãy nhớ rằng Python chỉ đơn giản là đang nói: “Tên bạn dùng không tồn tại trong phạm vi tôi có thể nhìn thấy.”
Bằng cách kiểm tra kỹ lưỡng chính tả, đảm bảo thứ tự thực thi chính xác, hiểu rõ sự khác biệt giữa Local và Global scope, và sử dụng các công cụ hỗ trợ hiện đại, bạn có thể nhanh chóng khắc phục và ngăn chặn NameError.
FAQ nhanh về NameError
Q: Tôi chắc chắn đã định nghĩa biến rồi, tại sao vẫn bị NameError?
A: Rất có thể biến đó được định nghĩa ở một Scope khác (ví dụ: bên trong một hàm) mà nơi bạn đang sử dụng không thể truy cập được. Hoặc, nếu dùng Jupyter, có thể bạn chưa chạy cell định nghĩa biến đó trong phiên làm việc hiện tại.
Q: Sự khác biệt giữa NameError và AttributeError là gì?
A: NameError có nghĩa là bản thân cái tên không tồn tại trong scope hiện tại. AttributeError có nghĩa là cái tên (đối tượng) tồn tại, nhưng bạn đang cố gắng truy cập một thuộc tính hoặc phương thức không có trên đối tượng đó (ví dụ: my_list.calculate() nếu list không có phương thức calculate).
Q: UnboundLocalError có phải là NameError không?
A: Về mặt kỹ thuật, UnboundLocalError là một lớp con của NameError. Nó xảy ra trong tình huống cụ thể khi một biến được coi là Local (do có phép gán trong hàm), nhưng lại được sử dụng trước khi nó được gán giá trị trong hàm đó
Q: Làm sao để tránh NameError hiệu quả nhất?
A: Sử dụng Linter (như Flake8) tích hợp trong IDE của bạn. Nó sẽ cảnh báo bạn ngay lập tức khi bạn sử dụng một tên chưa được định nghĩa.