Ép kiểu
Bạn sẽ học được
- Bốn hàm ép kiểu cơ bản và kết quả chính xác của chúng.
- Vì sao
int("3.14")lỗi nhưngint(3.14)chạy. bool()trên chuỗi gây bất ngờ lớn nhất trong Python.- Bảng giá trị "falsy" đầy đủ.
- Cách xử lý
ValueErrorkhi dữ liệu đầu vào không sạch.
Khái niệm cốt lõi
Ép kiểu là chuyển giá trị từ kiểu này sang kiểu khác bằng cách gọi hàm trùng tên kiểu:
print(int("42") + 1)
print(float("3.14") * 2)
print(str(42) + "!")
print(bool(1), bool(0))43
6.28
42!
True FalseBốn hàm int(), float(), str(), bool() là công cụ hằng ngày. Nhưng mỗi hàm có quy tắc riêng, và ba trong số đó thường xuyên gây bất ngờ.
int()
int() có hai việc: cắt phần thập phân của số, và đọc chuỗi thành số nguyên.
print(int(3.99))
print(int(-3.99))
print(int("42"))
print(int(" 42 "))
print(int(True), int(False))3
-3
42
42
1 0Hai điểm quan trọng:
Một, int() cắt về phía 0, không làm tròn xuống. int(-3.99) ra -3, trong khi -3.99 // 1 ra -4.0. Nếu cần làm tròn, dùng round() hoặc math.floor() tuỳ ý định.
Hai, chuỗi có khoảng trắng hai đầu vẫn đọc được, nhưng chuỗi có dấu thập phân thì không:
int("3.14")ValueError: invalid literal for int() with base 10: '3.14'Muốn đọc "3.14" thành số, phải qua float trước:
print(int(float("3.14")))3Đây là lỗi cực phổ biến khi đọc CSV: cột số có giá trị "3.0" từ Excel, int() báo lỗi. Cách xử lý đúng là int(float(x)) hoặc dùng Decimal/pandas để đọc cả cột.
int() còn nhận cơ số thứ hai:
print(int("1010", 2))
print(int("ff", 16))10
255float()
float() đọc chuỗi hoặc số thành số thực:
print(float("3.14"))
print(float("1e3"))
print(float(42))
print(float("inf"), float("-inf"))3.14
1000.0
42.0
inf -inffloat() chấp nhận ký hiệu khoa học, inf, -inf, nan. Với dữ liệu thật, nan (Not a Number) xuất hiện từ phép chia 0/0 hoặc từ cột trống trong file. So sánh nan == nan luôn False; dùng math.isnan().
Ép float sang int làm mất phần thập phân, không làm tròn. Nếu cần làm tròn, round():
print(round(3.5), round(4.5), round(2.5))4 4 2Kết quả thứ ba gây tranh cãi: Python dùng làm tròn ngân hàng (round half to even), nên 2.5 thành 2, 3.5 thành 4. Đây là hành vi có chủ đích, giảm sai lệch tích luỹ khi cộng nhiều số đã làm tròn.
str()
str() chuyển gần như mọi thứ thành chuỗi hiển thị:
print(str(42), str(3.14), str(True), str(None))
print(str([1, 2]), str({"a": 1}))42 3.14 True None
[1, 2] {'a': 1}str() dùng cho hiển thị, không dùng để tuần tự hoá dữ liệu. Muốn lưu cấu trúc để đọc lại, dùng json.dumps() (chương 5): str() tạo ra chuỗi mà eval() mới đọc lại được — và eval() trên dữ liệu không tin cậy là lỗ hổng bảo mật.
bool() — cái bẫy lớn nhất
bool() trả False cho một danh sách giá trị "rỗng", True cho phần còn lại:
| Giá trị | bool() |
|---|---|
0, 0.0, 0j | False |
"" (chuỗi rỗng) | False |
[], (), {}, set() | False |
None | False |
False | False |
| Mọi giá trị khác | True |
Bất ngờ nằm ở chuỗi:
print(bool("0"))
print(bool("False"))
print(bool(" "))
print(bool(""))True
True
True
FalseChuỗi "False" là chuỗi không rỗng, nên True. Chuỗi "0" cũng vậy. Đây là lý do đọc biến môi trường hoặc ô CSV dạng "false" rồi dùng trực tiếp trong if sẽ sai. Phải so sánh tường minh:
raw = "false"
is_enabled = raw.strip().lower() in {"true", "1", "yes"}
print(is_enabled)FalseTương tự, bool(" ") là True vì khoảng trắng vẫn là ký tự. Muốn coi chuỗi chỉ có khoảng trắng là rỗng, dùng bool(raw.strip()).
Xử lý ValueError
Ép kiểu có thể thất bại. Trong mã production, bắt lỗi thay vì để chương trình dừng:
def to_int(value: str) -> int | None:
try:
return int(value)
except (TypeError, ValueError):
return None
for raw in ["42", "3.14", "abc", ""]:
print(repr(raw), "→", to_int(raw))'42' → 42
'3.14' → None
'abc' → None
'' → Nonetry/except là cách Python xử lý lỗi dự kiến được. Chỉ bắt đúng loại lỗi (ValueError, TypeError), không dùng except: trần — nó nuốt cả lỗi lập trình và làm bug khó tìm.
Thực hành
- Chạy
int("42") + 1,float("3.14") * 2,str(42) + "!". - Thử
int("3.14"), đọc thông báo, rồi sửa bằngint(float("3.14")). - So sánh
int(-3.99)và-3.99 // 1. Giải thích khác biệt. - Kiểm tra
bool("0"),bool("False"),bool(" "),bool(""). - Viết hàm
to_intnhư trên và thử với bốn giá trị. - Đọc
"ff"ở cơ số 16 và"1010"ở cơ số 2.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
int("3.14") lỗi | Chuỗi có dấu thập phân | int(float(x)) |
int("") lỗi | Chuỗi rỗng | Kiểm tra rỗng trước |
bool("False") ra True | Chuỗi không rỗng | So sánh với tập giá trị |
float("1,5") lỗi | Dấu phẩy thập phân kiểu Việt Nam | Thay , bằng . trước |
| Làm tròn sai chiều | int() cắt về 0 | Dùng round() hoặc math.floor() |
round(2.5) ra 2 | Làm tròn ngân hàng | Dùng Decimal nếu cần luật khác |
| Ứng dụng crash vì dữ liệu bẩn | Không bắt ValueError | try/except đúng loại |
Tóm tắt
int()cắt về 0; không đọc được chuỗi có dấu thập phân.float()nhận ký hiệu khoa học,inf,nan.str()để hiển thị, không phải để tuần tự hoá.bool()chỉFalsevới giá trị rỗng —"0"và"False"đềuTrue.- Bắt
ValueErrorkhi dữ liệu đến từ bên ngoài.
Use ← → to move between lessons