Lỗi này là gì
Script Python của bạn bị crash với thông báo kiểu như:
AttributeError: 'NoneType' object has no attribute 'split'
Tên method sau has no attribute có thể thay đổi — bạn có thể thấy 'lower', 'strip', 'replace', hoặc bất kỳ string method nào khác. Nhưng bản chất luôn giống nhau: ở đâu đó trong code, một biến đang giữ giá trị None thay vì string (hoặc list, hoặc object) mà bạn mong đợi.
Nguyên nhân gốc rễ
None trong Python là kiểu dữ liệu riêng biệt, NoneType. Nó không có string method, không có list method — không có gì cả. Gọi .split() trên nó và Python sẽ báo cho bạn biết chính xác điều gì sai.
Chín trong mười trường hợp, nguyên nhân là một trong những cái này:
- Một function trả về
Nonengầm vì thiếu câu lệnhreturn - Một biến chưa được gán giá trị, hoặc bị gán tường minh thành
None - Regex match hoặc dictionary lookup không tìm thấy gì và trả về
None - Response từ API hoặc kết quả đọc file trả về rỗng
Chẩn đoán nhanh
Trước tiên, tìm xem biến nào đang là None. Thêm print() ngay trên dòng bị crash:
# Dòng bị crash:
result = user_input.split(",")
# Thêm dòng này phía trên:
print(type(user_input), repr(user_input))
Nếu bạn thấy <class 'NoneType'> None trong output, đó chính là biến cần tìm. Bây giờ hãy truy ngược lại xem nó nhận giá trị đó từ đâu — cách fix hầu như luôn nằm ở bước trước đó trong code.
Fix 1 — Kiểm tra function cung cấp giá trị
Thiếu câu lệnh return là nguyên nhân hàng đầu. Một function đi vào một nhánh điều kiện nhưng quên không return gì thì sẽ âm thầm trả về None.
# LỖI — trả về None ngầm
def get_username(data):
if data:
username = data["name"]
# quên return!
name = get_username({"name": "alice"})
parts = name.split(" ") # AttributeError
# ĐÃ SỬA
def get_username(data):
if data:
return data["name"]
return "" # hoặc raise exception
name = get_username({"name": "alice"})
parts = name.split(" ") # Hoạt động: ['alice']
Kiểm tra từng nhánh của function. Nếu bất kỳ nhánh nào có thể thoát ra mà không có return, Python sẽ tự động điền None — một cách âm thầm.
Fix 2 — Kiểm tra None trước khi dùng
Đôi khi None là kết quả hợp lệ — một trường tùy chọn, một config key bị thiếu, một response "không tìm thấy". Hãy kiểm tra trước khi gọi method:
value = some_function()
# Cách A: kiểm tra tường minh
if value is not None:
parts = value.split(",")
else:
parts = []
# Cách B: fallback viết gọn
parts = (value or "").split(",")
Cách B ngắn gọn hơn. Tuy nhiên cần chú ý — or "" cũng kích hoạt với string rỗng và 0, không chỉ riêng None. Khi sự phân biệt đó quan trọng, hãy dùng value is not None.
Fix 3 — Sửa lỗi Dictionary và Regex lookup
Hai built-in của Python trả về None âm thầm khi không tìm thấy gì: dict.get() và re.search().
# Dictionary — dùng giá trị mặc định
data = {"city": "Hanoi"}
country = data.get("country") # Trả về None
parts = country.split("-") # AttributeError
# Sửa: cung cấp fallback
country = data.get("country", "") # Trả về "" thay vì None
parts = country.split("-") # Hoạt động: ['']
import re
text = "hello world"
match = re.search(r"(\d+)", text) # Không có số — trả về None
result = match.group(1) # AttributeError
# Sửa: kiểm tra trước khi dùng
if match:
result = match.group(1)
else:
result = None
Fix 4 — Xử lý None từ nguồn bên ngoài
HTTP API, database và đọc file đều có một điểm chung: chúng có thể trả về không có gì. Một JSON response có thể thiếu một trường. Một database row có thể không tồn tại. Đừng bao giờ giả định dữ liệu bên ngoài luôn sạch sẽ.
import requests
response = requests.get("https://api.example.com/user/1")
data = response.json()
# Nguy hiểm
name = data.get("name")
first, last = name.split(" ") # AttributeError nếu name là None
# An toàn
name = data.get("name") or ""
if " " in name:
first, last = name.split(" ", 1)
else:
first, last = name, ""
Fix 5 — Dùng Type Annotation và validate sớm
Trong các project lớn, None có thể đi qua 3–4 lần gọi function trước khi cuối cùng gây crash ở đâu đó sâu trong logic. Điều đó khiến việc debug rất khó chịu. Giải pháp: validate ngay tại điểm đầu vào.
def process_input(text: str) -> list[str]:
if not isinstance(text, str):
raise TypeError(f"Expected str, got {type(text).__name__}")
return text.split(",")
# Hàm này raise TypeError rõ ràng ngay lập tức, thay vì AttributeError khó hiểu sau này
process_input(None)
Một lỗi TypeError: Expected str, got NoneType rõ ràng ở dòng 2 tốt hơn nhiều so với AttributeError chôn vùi ở đâu đó trên dòng 87 của một module khác.
Kiểm tra lại sau khi sửa
Kiểm tra nhanh trong Python REPL hoặc script test:
value = None
result = (value or "").split(",")
print(result) # Kết quả mong đợi: ['']
value = "a,b,c"
result = (value or "").split(",")
print(result) # Kết quả mong đợi: ['a', 'b', 'c']
Cả hai đều phải chạy sạch. Dùng pytest? Thêm test tường minh cho trường hợp None:
def test_handles_none_input():
assert process_csv(None) == []
assert process_csv("a,b") == ["a", "b"]
Checklist phòng tránh
- Mọi function có giá trị trả về đều cần có
returntường minh trên mọi nhánh — không có ngoại lệ - Dùng
dict.get(key, default)thay vìdict[key]khi key có thể vắng mặt - Luôn kiểm tra kết quả của
re.search()/re.match()trước khi gọi.group() - Validate dữ liệu bên ngoài (API, DB, user input) ngay tại điểm đầu vào, không chôn sâu trong logic
- Chạy
mypyhoặcpyright— chúng phát hiện lỗi dùng saiOptional[str]trước khi code chạy

