DHDataHọc
TheoryLesson 10/305 min read+10 XP

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ác if 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:

code
values = [False, None, 0, 0.0, "", [], {}, set(), ()]
print([bool(v) for v in values])
code
[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":

code
print(bool("0"), bool("False"), bool(" "), bool([0]))
code
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:

code
print(0 == False, 0.0 == False, "" == False, [] == False)
code
True True False False

bool 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:

code
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à False

Cả 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:

code
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))
code
Chưa nhập số lượng
Chưa nhập số lượng

Số 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:

code
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":

code
def gia(price):
    return price or 1000

print(gia(None), gia(0), gia(500))
code
1000 1000 500

gia(0) trả 1000 dù 0 là giá hợp lệ. Cách viết an toàn:

code
def gia(price):
    return 1000 if price is None else price

Hoặ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:

code
x = None
print(x is None)
print([1] is None)
code
True
False

x == 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:

code
scores = [85, 92, 78]
print(all(s >= 50 for s in scores))
print(any(s >= 90 for s in scores))
print(all([]), any([]))
code
True
True
True False
  • all() đú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:

code
numbers = [2, 4, 6, 7, 8]
print(any(n % 2 == 1 for n in numbers))
code
True

Chỉ 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:

code
rows = [{"age": 25}, {"age": 31}, {"age": 19}]
print(all(r["age"] >= 18 for r in rows))

Thực hành

  1. In bool() của chín giá trị falsy và ba giá trị truthy trông như sai.
  2. So sánh 0 == False với "" == False, giải thích.
  3. Viết hàm nhận qty và phân biệt None, 0, số dương.
  4. Thử price or 1000 với price = 0 và sửa bằng is None.
  5. Dùng all() kiểm tra mọi điểm trong danh sách đều từ 50 trở lên.
  6. Dùng any() tìm xem có phần tử lẻ nào không.

Lỗi thường gặp

Triệu chứngNguyên nhânCách sửa
Số 0 bị coi là thiếuDùng if not valueif value is None
"0" được coi là đúngChuỗi khác rỗngÉp số trước khi kiểm tra
x == False đúng với 0bool là con của intDùng is False hoặc kiểm tra kiểu
or thay mất 0/""or trả toán hạngKiểm tra is None tường minh
== None báo lintSo sánh giá trị thay danh tínhis None
all() trả True với list rỗngKhông có phản ví dụKiểm tra độ dài nếu cần
any() trả False với list rỗngKhông có phần tử đúngKiể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 "" == False sai — đừng nhầm ép kiểu với so sánh.
  • if value: gộp "thiếu" và "bằng 0"; dùng is None khi cần phân biệt.
  • all()/any() dừng sớm; rỗng trả True/False theo thứ tự.

Use ← → to move between lessons