Sửa lỗi TypeError: 'NoneType' object is not iterable trong Python

beginner🐍 Python2026-04-22| Python 3.x trên Linux, macOS, Windows

Error Message

TypeError: 'NoneType' object is not iterable
#python#typeerror#none#iteration#debugging

Lỗi Gặp Phải

Bạn đang lặp qua một thứ gì đó — kết quả từ hàm, một hàng trong database, một phản hồi API — và Python ném ra:

TypeError: 'NoneType' object is not iterable

Dịch ra: bạn đã cố lặp qua None. Mọi cơ chế lặp trong Python — vòng for, list comprehension, tuple unpacking, toán tử * spread — đều cần một iterable thực sự. None không phải vậy.

Đây là cách đơn giản nhất để kích hoạt lỗi này:

def get_users():
    pass  # forgot to return anything

for user in get_users():  # TypeError here
    print(user)

Nguyên Nhân Gốc Rễ

Bất kỳ hàm Python nào không có câu lệnh return tường minh đều âm thầm trả về None. Đó là đặc tả ngôn ngữ, không phải lỗi. Nhưng một số pattern khác cũng tạo ra cái bẫy tương tự:

  • Một hàm trả về None ở một nhánh bạn không để ý tới — ví dụ một if không có else tương ứng
  • Các phương thức in-place như list.sort() hay dict.update() thay đổi đối tượng và luôn luôn trả về None
  • Một truy vấn ORM, con trỏ database, hoặc lời gọi API trả về None khi tập kết quả rỗng
  • Bạn gán kết quả trả về của một trong các phương thức in-place đó vào một biến

Cái cuối cùng liên tục làm các lập trình viên vấp ngã. Đây là hình dạng của nó:

items = [3, 1, 2]
items = items.sort()  # sort() returns None, not the sorted list!

for item in items:  # TypeError: 'NoneType' object is not iterable
    print(item)

items lúc này là None. Danh sách gốc đã được sắp xếp — nhưng bạn đã vứt bỏ tham chiếu đến nó.

Cách Khắc Phục

Cách 1: Kiểm tra xem hàm thực sự trả về gì

Trước khi lặp, hãy in hoặc kiểm tra giá trị:

result = get_users()
print(type(result), result)  # Debug: see what you actually got

Nếu đầu ra là <class 'NoneType'> None, hàm không trả về thứ bạn mong đợi. Tìm nó và thêm câu lệnh return:

def get_users():
    users = db.query("SELECT * FROM users")
    return users  # was missing before

Cách 2: Bảo vệ bằng kiểm tra None tường minh

Đôi khi None là kết quả hợp lệ — không tìm thấy kết quả, không có gì để xử lý. Hãy kiểm tra trước khi lặp:

users = get_users()

if users is not None:
    for user in users:
        print(user)

Hoặc gộp lại thành một dòng:

for user in (users or []):
    print(user)

Phần or [] thay thế bằng danh sách rỗng khi usersNone. Vòng lặp chạy không lần nào và không có ngoại lệ nào được ném ra.

Cách 3: Mặc định trả về collection rỗng bên trong hàm

Sửa từng chỗ gọi hàm rất mệt mỏi. Thay vào đó, hãy sửa hàm một lần duy nhất:

def get_users():
    result = db.query("SELECT * FROM users")
    if result is None:
        return []  # always return a list
    return result

Các nơi gọi hàm giờ có thể lặp tự do. Không cần kiểm tra ở mỗi chỗ sử dụng.

Cách 4: Khắc phục bẫy gán kết quả phương thức in-place

list.sort(), list.reverse(), dict.update(), và set.add() đều thay đổi in-place. Chúng trả về None. Đừng gán kết quả của chúng:

# Wrong
items = items.sort()

# Correct: sort in place, keep the reference
items.sort()

# Or use sorted() — it returns a new list
items = sorted(items)

Cách 5: Xử lý None từ các lời gọi nối chuỗi

Gọi phương thức theo chuỗi che giấu None cho đến khi nó bùng phát. Đây là cách viết rủi ro:

# response.json() might return None
for item in response.json().get("results"):
    process(item)

Hãy tách ra và kiểm tra từng bước:

data = response.json()
results = data.get("results") if data else []
for item in (results or []):
    process(item)

Cách 6: Toán tử walrus (Python 3.8+)

Khi hàm là từ bên ngoài và bạn không thể thay đổi kiểu trả về của nó, toán tử walrus gọn hơn so với kiểm tra hai dòng:

if (users := get_users()) is not None:
    for user in users:
        print(user)

Tìm Nguồn Gốc Của None

Đọc toàn bộ traceback. Python chỉ ra chính xác dòng bị lỗi:

Traceback (most recent call last):
  File "app.py", line 12, in process_orders
    for order in get_orders(user_id):
TypeError: 'NoneType' object is not iterable

Đến dòng 12. Iterable là get_orders(user_id). Thêm một lệnh in debug phía trên:

result = get_orders(user_id)
print(f"get_orders returned: {result!r}")
for order in result:
    ...

Định dạng !r gọi repr() trên giá trị. Nó phân biệt rõ ràng None với chuỗi rỗng '' hay danh sách rỗng [] — cả ba trông khác nhau trong đầu ra repr.

Kiểm Chứng

Chạy lại code sau khi sửa. Không có TypeError nghĩa là đã thành công. Để xác nhận nhánh kiểm tra xử lý None đúng cách, hãy mô phỏng tường minh:

def get_users():
    return None  # simulate no results

users = get_users()
for user in (users or []):
    print(user)

print("Done — no error")

Đầu ra mong đợi:

Done — no error

Phần thân vòng lặp bị bỏ qua. Không có ngoại lệ. Đó là hành vi bạn muốn.

Phòng Ngừa

  • Thêm type hint: def get_users() -> list[User]: ghi lại kiểu trả về mong đợi. Chạy mypy và nó sẽ đánh dấu bất kỳ đường code nào trả về None thay vì đó.
  • Trung thực với Optional: Nếu một hàm có thể hợp lệ trả về None, hãy chú thích nó là Optional[list]. Điều đó báo hiệu cho người gọi: hãy kiểm tra trước khi lặp.
  • Không bao giờ gán kết quả phương thức in-place: sort(), reverse(), update(), append() — tất cả đều trả về None. Hãy khắc cốt ghi tâm điều này.
  • Trả về collection rỗng, không phải None: Một hàm lấy danh sách nên trả về [] khi kết quả rỗng, không phải None. Hãy dành None cho trường hợp "giá trị này không tồn tại" — không phải "tôi không tìm thấy gì."

Related Error Notes