Fix AttributeError: 'NoneType' object has no attribute trong Python

beginner🐍 Python2026-03-17| Python 2.7 / Python 3.x trên Linux, macOS, Windows

Error Message

AttributeError: 'NoneType' object has no attribute 'split'
#python#attributeerror#nonetype#debugging

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ề None ngầm vì thiếu câu lệnh return
  • 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()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ó return tườ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 mypy hoặc pyright — chúng phát hiện lỗi dùng sai Optional[str] trước khi code chạy

Related Error Notes