Ép kiểu (type casting) và nhận dữ liệu từ người dùng qua input()
Thời lượng: ~8 giờ | Tuần: 4–5 (chia 2 tuần)
Tuần 4: Mục 1–5 | Tuần 5: Mục 6–10
PHẦN 1 — TUẦN 4
1. Biến là gì?
1.1. Định nghĩa
Variable (biến) là một cái tên trỏ tới một giá trị trong bộ nhớ.
so_luong = 10
Đọc là: “gán giá trị 10 cho biến so_luong”, hoặc “so_luong bây giờ trỏ tới giá trị 10”.
Ký hiệu
Thuật ngữ
Vai trò
so_luong
identifier (định danh)
Tên bạn tự đặt
=
assignment operator (toán tử gán)
Gán giá trị bên phải cho tên bên trái
10
value (giá trị)
Dữ liệu thật
Dấu = KHÔNG phải "bằng nhau"
Trong toán học, x = 10 nghĩa là “x bằng 10”. Trong lập trình, = là hành động gán. Để so sánh bằng nhau, Python dùng == (hai dấu bằng) — học ở 04 - Toán tử và biểu thức.
Điều này giống T-SQL: SET @x = 10 là gán, còn WHERE MaKH = 'KH001' là so sánh. Python dùng = cho gán và == cho so sánh, rạch ròi hơn.
1.2. Không cần khai báo kiểu
So sánh cách khai báo biến:
T-SQL:
DECLARE @SoLuong INT;SET @SoLuong = 10;
C#:
int soLuong = 10;
Python:
so_luong = 10
Python tự suy ra kiểu dữ liệu từ giá trị bạn gán. Đây gọi là type inference (suy luận kiểu).
1.3. Biến trong Python là “nhãn dán”, không phải “cái hộp”
Đây là điểm khác biệt quan trọng so với C# hay Java.
Trong nhiều ngôn ngữ, biến giống một cái hộp có kích thước cố định, chứa giá trị bên trong. Trong Python, biến giống một tờ nhãn dán lên một đối tượng nằm trong bộ nhớ.
a = 100b = a # b dán nhãn lên CÙNG một đối tượng với aprint(a, b) # 100 100a = 200 # a được gỡ ra, dán sang đối tượng 200print(a, b) # 200 100 <- b vẫn dán ở 100
Kiểm chứng bằng hàm id() (trả về địa chỉ đối tượng trong bộ nhớ):
a = 100b = aprint(id(a)) # ví dụ: 140705234567890print(id(b)) # cùng số -> cùng một đối tượnga = 200print(id(a)) # số khác -> đã trỏ sang đối tượng khácprint(id(b)) # vẫn là số cũ
Vì sao cần hiểu điều này ngay từ đầu?
Với số và chuỗi, sự khác biệt không gây hậu quả. Nhưng khi tới list ở 08 - List và Tuple, hiểu nhầm điểm này sẽ khiến bạn gặp lỗi rất khó hiểu (sửa list này thì list kia cũng đổi theo).
2. Quy tắc đặt tên biến
2.1. Bắt buộc (sai là lỗi)
Quy tắc
Ví dụ đúng
Ví dụ sai
Bắt đầu bằng chữ cái hoặc _
ten, _tam
1ten ❌
Chỉ chứa chữ, số, _
ma_kh_01
ma-kh ❌, ma kh ❌, ma@kh ❌
Không trùng từ khóa
lop_hoc
class ❌, if ❌
Phân biệt hoa/thường
ten ≠ Ten ≠ TEN
—
2.2. Khuyến nghị theo PEP 8
# ✅ TỐT — snake_case, tên có nghĩatong_doanh_thu = 5000000ma_khach_hang = "KH001"ngay_lap_chung_tu = "2026-08-08"# ⚠️ CHẠY ĐƯỢC NHƯNG XẤUTongDoanhThu = 5000000 # PascalCase — dành cho classtongDoanhThu = 5000000 # camelCase — của Java/C#, không phải Pythonx = 5000000 # tên vô nghĩatdt = 5000000 # viết tắt khó hiểu# ❌ LỖItong-doanh-thu = 5000000 # SyntaxError — dấu gạch ngang là phép trừ2026_doanh_thu = 5000000 # SyntaxError — bắt đầu bằng số
Sau khi ghi đè, bạn không thể dùng các hàm đó nữa trong file này:
print = "xin chao"print("thu in") # ❌ TypeError: 'str' object is not callable
Cách nhận biết
VS Code sẽ tô màu khác cho các tên có sẵn (built-in). Nếu tên biến bạn định đặt bị tô màu đặc biệt, hãy đổi tên. Ví dụ dùng danh_sach thay cho list, kieu_kh thay cho type.
3. Kiểu dữ liệu int — Số nguyên
3.1. Cơ bản
tuoi = 35so_luong = 1200nhiet_do = -5nam = 2026
3.2. Không giới hạn độ lớn
Đây là điểm mạnh đặc biệt của Python. Trong T-SQL, INT chỉ chứa tới khoảng 2,1 tỷ; BIGINT tới khoảng 9,2 triệu tỷ. Python không có giới hạn (chỉ giới hạn bởi RAM):
Không tràn số (overflow), không cần khai báo BIGINT.
3.3. Dấu gạch dưới cho dễ đọc
tien_luong = 25_000_000 # Đọc là 25 triệuprint(tien_luong) # In ra: 25000000
Python bỏ qua dấu _, nó chỉ để cho người đọc. Rất tiện khi làm việc với số tiền lớn.
3.4. Hệ cơ số khác
nhi_phan = 0b1010 # 10 trong hệ nhị phân (binary)bat_phan = 0o17 # 15 trong hệ bát phân (octal)thap_luc_phan = 0xFF # 255 trong hệ thập lục phân (hexadecimal)print(nhi_phan, bat_phan, thap_luc_phan) # 10 15 255
4.3. ⚠️ Vấn đề sai số của số thực (RẤT QUAN TRỌNG VỚI DÂN KẾ TOÁN)
Chạy thử đoạn này:
print(0.1 + 0.2)
Kết quả:
0.30000000000000004
Và:
print(0.1 + 0.2 == 0.3) # False !!!
Nguyên nhân: Máy tính lưu số thực theo chuẩn IEEE 754 dưới dạng nhị phân. Số 0.1 trong hệ thập phân là số vô hạn tuần hoàn trong hệ nhị phân — giống như 1/3 = 0.3333... không biểu diễn hết được trong hệ thập phân. Vì vậy máy chỉ lưu được giá trị gần đúng.
Đây không phải lỗi của Python. Mọi ngôn ngữ dùng float đều vậy: C#, Java, JavaScript, và cả kiểu FLOAT/REAL trong SQL Server.
Tuyệt đối không dùng float cho tiền tệ
Với phần mềm tài chính kế toán, sai số này tích lũy qua hàng triệu bản ghi sẽ gây lệch sổ. Đây chính là lý do trong SQL Server bạn dùng DECIMAL(18,2) hoặc MONEY thay vì FLOAT.
Giải pháp trong Python: dùng module decimal
from decimal import Decimal# ❌ Sai sốprint(0.1 + 0.2) # 0.30000000000000004# ✅ Chính xác — chú ý truyền vào dạng CHUỖIprint(Decimal("0.1") + Decimal("0.2")) # 0.3print(Decimal("0.1") + Decimal("0.2") == Decimal("0.3")) # True
ten = "Nguyen Van A" # Nháy képdia_chi = 'Hue, Viet Nam' # Nháy đơn — tương đương
Python chấp nhận cả hai. PEP 8 không bắt buộc chọn loại nào, nhưng hãy nhất quán trong một dự án.
5.2. Vì sao có 2 loại nháy?
Để lồng nhau mà không cần escape:
cau_1 = "Anh ay noi: 'Xin chao'" # Nháy đơn bên trong nháy képcau_2 = 'File ten la "bao_cao.txt"' # Nháy kép bên trong nháy đơnprint(cau_1)print(cau_2)
5.3. Chuỗi nhiều dòng
mo_ta = """Dong 1Dong 2Dong 3"""print(mo_ta)
5.4. Số nằm trong nháy là CHUỖI, không phải số
a = 10 # intb = "10" # strprint(a + a) # 20 (phép cộng số học)print(b + b) # 1010 (phép nối chuỗi)print(a + b) # ❌ TypeError: unsupported operand type(s) for +: 'int' and 'str'
Đây là lỗi phổ biến nhất của người mới. Ghi nhớ: có nháy = chuỗi.
PHẦN 2 — TUẦN 5
6. Kiểu dữ liệu bool — Luận lý
6.1. Hai giá trị duy nhất
da_thanh_toan = Trueda_huy = False
Viết hoa chữ cái đầu
Python dùng True và False — chữ T và F viết hoa. Viết true/false (như JavaScript, SQL) sẽ báo NameError.
Mọi giá trị trong Python đều có thể coi như đúng/sai khi đặt vào ngữ cảnh điều kiện.
Các giá trị FALSY (được coi là sai):
print(bool(0)) # False — số 0print(bool(0.0)) # False — số thực 0print(bool("")) # False — chuỗi rỗngprint(bool([])) # False — list rỗngprint(bool({})) # False — dict rỗngprint(bool(())) # False — tuple rỗngprint(bool(None)) # False — None
Mọi thứ khác đều TRUTHY (được coi là đúng):
print(bool(1)) # Trueprint(bool(-5)) # True — số âm vẫn là Trueprint(bool("0")) # True — chuỗi "0" KHÔNG rỗng nên là Trueprint(bool("False")) # True — chuỗi "False" KHÔNG rỗng nên là Trueprint(bool([0])) # True — list có 1 phần tửprint(bool(" ")) # True — chuỗi có 1 dấu cách, không rỗng
Bẫy hay gặp
bool("0") và bool("False") đều trả về True, vì đó là chuỗi không rỗng. Chỉ có chuỗi rỗng "" mới là falsy.
None là một giá trị đặc biệt, nghĩa là “không có giá trị” hoặc “chưa xác định”.
ngay_thanh_toan = None # Chưa thanh toán nên chưa có ngàyghi_chu = None # Không có ghi chú
7.2. So sánh với NULL trong SQL
SQL NULL
Python None
Ý nghĩa
Không có giá trị
Không có giá trị
Cách kiểm tra
WHERE Col IS NULL
if x is None:
NULL = NULL
Trả về UNKNOWN (không phải TRUE)
None == None trả về True
Trong phép tính
5 + NULL = NULL (lan truyền)
5 + None → ❌ TypeError
Khác biệt lớn nhất
Trong SQL, NULLlan truyền âm thầm qua phép tính. Trong Python, dùng None trong phép tính sẽ báo lỗi ngay:
x = Noneprint(x + 5) # ❌ TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Đây là ưu điểm: lỗi lộ ra ngay thay vì âm thầm cho ra kết quả sai.
7.3. Kiểm tra None — dùng is, không dùng ==
x = Noneif x is None: # ✅ ĐÚNG — cách chuẩn print("Chua co gia tri")if x == None: # ⚠️ Chạy được nhưng KHÔNG chuẩn print("Chua co gia tri")
PEP 8 quy định rõ: so sánh với Nonephải dùng is hoặc is not.
Lý do: is so sánh danh tính đối tượng (có phải cùng một đối tượng trong bộ nhớ không), còn == so sánh giá trị. Vì None là đối tượng duy nhất (singleton), is vừa nhanh hơn vừa chính xác hơn.
gia_tri = Noneif gia_tri is not None: print("Da co gia tri")else: print("Chua co gia tri")
7.4. None khác với 0 và ""
a = None # Chưa có giá trịb = 0 # Có giá trị, giá trị đó là số 0c = "" # Có giá trị, giá trị đó là chuỗi rỗngprint(a is None) # Trueprint(b is None) # Falseprint(c is None) # False
Trong nghiệp vụ kế toán, sự phân biệt này rất có ý nghĩa: so_du = 0 (tài khoản có số dư bằng 0) khác hoàn toàn so_du = None (chưa xác định được số dư).
Trong T-SQL, DECLARE @x INT thì @x mãi mãi là INT. Python không như vậy.
Ưu điểm
Nhược điểm
Dynamic typing
Viết nhanh, linh hoạt, ít code rườm rà
Lỗi kiểu chỉ lộ ra khi chạy tới dòng đó
Mặt trái của dynamic typing
tong = 0tong = "0" # Vô tình gán nhầm chuỗitong = tong + 100 # ❌ TypeError — nhưng chỉ phát hiện KHI CHẠY TỚI ĐÂY
Trong chương trình dài, lỗi này có thể nằm ở dòng 500 và chỉ xuất hiện trong một trường hợp hiếm gặp. Đây là lý do người ta phát triển type hints (gợi ý kiểu) — bạn sẽ học sau khi hoàn thành lộ trình.
8.4. Type hints — Xem trước (chưa cần dùng)
so_luong: int = 10ten: str = "Nguyen Van A"gia: float = 15000.5
Dấu : int là type hint. Python không ép buộc nó — bạn vẫn gán được kiểu khác, nhưng VS Code sẽ cảnh báo. Đây là chủ đề nâng cao, cứ ghi nhớ là có, chưa cần dùng ngay.
9. Type Casting — Ép kiểu
9.1. Các hàm ép kiểu
Hàm
Chuyển sang
Ví dụ
int(x)
Số nguyên
int("10") → 10
float(x)
Số thực
float("10.5") → 10.5
str(x)
Chuỗi
str(10) → "10"
bool(x)
Luận lý
bool(0) → False
9.2. Ví dụ
# Chuỗi -> Sốprint(int("100")) # 100print(float("15.5")) # 15.5# Số -> Chuỗiprint(str(100)) # "100"print("Tuoi: " + str(35)) # Tuoi: 35# Số thực -> Số nguyên (CẮT BỎ phần thập phân, KHÔNG làm tròn)print(int(9.99)) # 9 <- không phải 10!print(int(-9.99)) # -9 <- cắt về phía 0print(int(9.5)) # 9# Muốn làm tròn thì dùng round()print(round(9.99)) # 10print(round(9.5)) # 10print(round(2.5)) # 2 <- chú ý! xem mục 9.4print(round(15.6789, 2)) # 15.68 — làm tròn 2 chữ số thập phân
9.3. Ép kiểu thất bại
print(int("abc")) # ❌ ValueError: invalid literal for int() with base 10: 'abc'print(int("10.5")) # ❌ ValueError — int() không nhận chuỗi có dấu chấmprint(int("")) # ❌ ValueErrorprint(int(None)) # ❌ TypeError
Cách xử lý đúng cho "10.5":
print(int(float("10.5"))) # 10 — qua float trước, rồi mới sang int
print(round(0.5)) # 0 <- KHÔNG phải 1!print(round(1.5)) # 2print(round(2.5)) # 2 <- KHÔNG phải 3!print(round(3.5)) # 4
Python dùng banker’s rounding (làm tròn ngân hàng, còn gọi là round half to even — làm tròn về số chẵn gần nhất). Quy tắc này được chuẩn IEEE 754 quy định, nhằm tránh thiên lệch khi cộng dồn hàng triệu số.
Nếu cần làm tròn theo kiểu “0.5 lên trên” như thông thường:
from decimal import Decimal, ROUND_HALF_UPdef lam_tron_thuong(so, chu_so=0): """Làm tròn theo quy tắc 0.5 làm tròn lên.""" return Decimal(str(so)).quantize(Decimal("1." + "0" * chu_so) if chu_so else Decimal("1"), rounding=ROUND_HALF_UP)print(lam_tron_thuong(2.5)) # 3print(lam_tron_thuong(15.675, 2)) # 15.68
Liên hệ với SQL Server
Hàm ROUND() trong T-SQL dùng round half away from zero (0.5 làm tròn ra xa số 0), tức ROUND(2.5, 0) = 3. Python mặc định khác. Khi viết chương trình đối chiếu số liệu với hệ thống ERP, đây là nguồn lệch số rất dễ bỏ sót.
9.5. Ép kiểu ngầm định (implicit conversion)
Python tự nâng kiểu trong một số trường hợp:
print(10 + 5.5) # 15.5 — int tự nâng thành floatprint(type(10 + 5.5)) # <class 'float'>print(True + 10) # 11 — bool tự nâng thành int
Nhưng không tự chuyển giữa số và chuỗi:
print("10" + 5) # ❌ TypeErrorprint("10" * 3) # "101010" — đây là NHÂN BẢN chuỗi, không phải phép nhân số!
10. input() — Nhận dữ liệu từ người dùng
10.1. Cơ bản
ten = input("Nhap ten cua ban: ")print("Xin chao,", ten)
Chạy:
Nhap ten cua ban: Nguyen Van A
Xin chao, Nguyen Van A
10.2. ⚠️ input() LUÔN trả về chuỗi
Đây là lỗi kinh điển của người mới:
tuoi = input("Nhap tuoi: ") # Người dùng gõ: 35print(type(tuoi)) # <class 'str'> <- CHUỖI, không phải số!print(tuoi + 1) # ❌ TypeError
# Gán song songa, b, c = 1, 2, 3print(a, b, c) # 1 2 3# Hoán đổi giá trị — không cần biến trung gianx, y = 10, 20x, y = y, xprint(x, y) # 20 10# Gán cùng một giá trị cho nhiều biếnp = q = r = 0print(p, q, r) # 0 0 0
Cú pháp hoán đổi x, y = y, x là đặc trưng rất được ưa chuộng của Python. Trong các ngôn ngữ khác bạn phải viết 3 dòng với biến tạm.
11. Thực hành bắt buộc
Bài 1 — Khám phá kiểu dữ liệu
Viết file tuan-04/kieu_du_lieu.py, in ra giá trị và kiểu của từng biểu thức:
Dự đoán kết quả trước khi chạy, sau đó chạy để đối chiếu:
print(int("42"))print(int(3.99))print(int(-3.99))print(float("3"))print(str(3.14) + " la so pi")print(bool(""))print(bool(" "))print(bool("0"))print(bool([]))print(round(2.5))print(round(3.5))print(round(1.2345, 2))
Bài 3 — Diện tích và chu vi
Viết chương trình nhận vào chiều dài, chiều rộng hình chữ nhật, in ra diện tích và chu vi.
Nhap chieu dai (m): 5.5
Nhap chieu rong (m): 3.2
Dien tich: 17.6 m2
Chu vi : 17.4 m
Bài 4 — Đổi tiền
Nhập số tiền VND và tỷ giá, in ra số tiền quy đổi sang USD, làm tròn 2 chữ số.