Truthiness và dữ liệu thiếu
Bạn sẽ học được
- Những giá trị nào Python coi là "sai".
- Vì sao
if value:khácif value is not None:. - Cái bẫy khi dùng
orđể đặt giá trị mặc định cho số. all()/any()và cách chúng dừng sớm.- Cách viết điều kiện kiểm tra dữ liệu thiếu chính xác hơn.
Khái niệm cốt lõi
Python không bắt điều kiện phải là True/False. Bất kỳ giá trị nào cũng được "đọc" thành đúng/sai qua bool(). Nhóm falsy — bị coi là sai — chỉ gồm:
values = [False, None, 0, 0.0, "", [], {}, set(), ()]
print([bool(v) for v in values])[False, False, False, False, False, False, False, False, False]Mọi thứ còn lại là truthy, kể cả những giá trị trông như "sai":
print(bool("0"), bool("False"), bool(" "), bool([0]))True True True True"0" là chuỗi có một ký tự nên đúng. "False" là chuỗi năm ký tự nên đúng. " " là chuỗi chứa dấu cách nên đúng. [0] là danh sách có một phần tử nên đúng. Quy tắc chỉ dựa trên độ dài/rỗng, không dựa trên nội dung.
== False khác bool(...) == False
Hai phép kiểm tra này hay bị nhầm:
print(0 == False, 0.0 == False, "" == False, [] == False)True True False Falsebool là lớp con của int trong Python, nên False == 0 và True == 1. Vì vậy 0 == False đúng. Nhưng "" và [] không bằng False — chúng chỉ bị ép thành sai khi dùng trong điều kiện. Đây là lý do phải phân biệt:
value = 0
if value == False:
print("nhánh A") # chạy, vì 0 == False
if not value:
print("nhánh B") # cũng chạy, vì bool(0) là FalseCả hai cùng chạy ở ví dụ này, nhưng với value = "" thì chỉ nhánh B chạy. Khi đọc code, hãy tự hỏi tác giả muốn kiểm tra giá trị hay độ rỗng.
if value: không phân biệt "không có" với "bằng 0"
Đây là lỗi tốn tiền nhất trong xử lý dữ liệu:
def hien_thi_so_luong(qty):
if qty:
return f"Còn {qty} sản phẩm"
return "Chưa nhập số lượng"
print(hien_thi_so_luong(0))
print(hien_thi_so_luong(None))Chưa nhập số lượng
Chưa nhập số lượngSố lượng 0 là dữ liệu hợp lệ — hết hàng — nhưng bị báo thành "chưa nhập". Trong báo cáo doanh thu, đơn hàng giá trị 0 sẽ bị loại khỏi tổng. Sửa bằng cách kiểm tra rỗng tường minh:
def hien_thi_so_luong(qty):
if qty is None:
return "Chưa nhập số lượng"
if qty == 0:
return "Hết hàng"
return f"Còn {qty} sản phẩm"Nguyên tắc: dùng is None khi ý nghĩa là "thiếu dữ liệu", dùng if not x chỉ khi "rỗng" và "thiếu" thực sự cùng một nghĩa với bạn — ví dụ danh sách kết quả tìm kiếm.
or làm mặc định và cái bẫy số 0
Như bài điều kiện đã nói, or trả toán hạng đầu tiên "đúng":
def gia(price):
return price or 1000
print(gia(None), gia(0), gia(500))1000 1000 500gia(0) trả 1000 dù 0 là giá hợp lệ. Cách viết an toàn:
def gia(price):
return 1000 if price is None else priceHoặc dùng dict.get với mặc định, nhưng vẫn cùng vấn đề nếu giá trị lưu là None so với 0. Trong Python 3.12+, có thể viết gọn hơn bằng cách kiểm tra is None trước.
is None, không phải == None
None là một đối tượng duy nhất trong toàn bộ chương trình, nên so sánh danh tính là đúng và nhanh:
x = None
print(x is None)
print([1] is None)True
Falsex == None thường cho cùng kết quả, nhưng có thể bị lớp tự định nghĩa __eq__ làm sai. Công cụ lint (ruff, flake8) sẽ cảnh báo E711. Luôn dùng is None / is not None.
all() và any()
Hai hàm này nhận iterable và trả một giá trị đúng/sai:
scores = [85, 92, 78]
print(all(s >= 50 for s in scores))
print(any(s >= 90 for s in scores))
print(all([]), any([]))True
True
True Falseall()đúng khi mọi phần tử đúng. Với iterable rỗng trảTrue(không có phản ví dụ).any()đúng khi ít nhất một phần tử đúng. Với iterable rỗng trảFalse.
Cả hai dừng sớm: all dừng ở phần tử sai đầu tiên, any dừng ở phần tử đúng đầu tiên. Nhờ vậy có thể dùng với generator để tránh tính toán thừa:
numbers = [2, 4, 6, 7, 8]
print(any(n % 2 == 1 for n in numbers))TrueChỉ cần chạm tới 7 là dừng. Với danh sách lớn, viết any(...) thay vì vòng lặp đầy đủ nhanh hơn và rõ ý hơn.
Kiểm tra "mọi phần tử đều hợp lệ" là mẫu rất hay gặp khi validate dữ liệu:
rows = [{"age": 25}, {"age": 31}, {"age": 19}]
print(all(r["age"] >= 18 for r in rows))Thực hành
- In
bool()của chín giá trị falsy và ba giá trị truthy trông như sai. - So sánh
0 == Falsevới"" == False, giải thích. - Viết hàm nhận
qtyvà phân biệtNone,0, số dương. - Thử
price or 1000vớiprice = 0và sửa bằngis None. - Dùng
all()kiểm tra mọi điểm trong danh sách đều từ 50 trở lên. - Dùng
any()tìm xem có phần tử lẻ nào không.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
Số 0 bị coi là thiếu | Dùng if not value | if value is None |
"0" được coi là đúng | Chuỗi khác rỗng | Ép số trước khi kiểm tra |
x == False đúng với 0 | bool là con của int | Dùng is False hoặc kiểm tra kiểu |
or thay mất 0/"" | or trả toán hạng | Kiểm tra is None tường minh |
== None báo lint | So sánh giá trị thay danh tính | is None |
all() trả True với list rỗng | Không có phản ví dụ | Kiểm tra độ dài nếu cần |
any() trả False với list rỗng | Không có phần tử đúng | Kiểm tra độ dài nếu cần |
Tóm tắt
- Falsy:
False,None,0,0.0,"", và mọi container rỗng. - Truthy: mọi chuỗi khác rỗng, kể cả
"0","False"," ". 0 == Falseđúng nhưng"" == Falsesai — đừng nhầm ép kiểu với so sánh.if value:gộp "thiếu" và "bằng 0"; dùngis Nonekhi cần phân biệt.all()/any()dừng sớm; rỗng trảTrue/Falsetheo thứ tự.
Use ← → to move between lessons