M04 — Toán tử và Biểu thức

← 03 - Biến và kiểu dữ liệu | Tiếp theo → 05 - Chuỗi ký tự (String)

Mục tiêu module

  • Nắm đủ 5 nhóm operator (toán tử): số học, so sánh, logic, gán, đồng nhất
  • Hiểu operator precedence (độ ưu tiên toán tử)
  • Hiểu short-circuit evaluation (tính toán rút gọn)
  • Phân biệt == và is

Thời lượng: ~4 giờ | Tuần: 6


1. Toán tử số học (Arithmetic Operators)

Toán tửTênVí dụKết quả
+Cộng7 + 310
-Trừ7 - 34
*Nhân7 * 321
/Chia thực7 / 32.3333333333333335
//Chia lấy nguyên (floor division)7 // 32
%Chia lấy dư (modulo)7 % 31
**Lũy thừa7 ** 3343

1.1. / luôn trả về float

print(10 / 2)          # 5.0   <- CÓ dấu chấm 0, là float
print(type(10 / 2))    # <class 'float'>
print(10 // 2)         # 5     <- int
print(type(10 // 2))   # <class 'int'>

Khác biệt với Python 2 và với SQL

  • Trong Python 2, 10 / 3 cho 3 (chia nguyên). Python 3 đổi thành 3.333.... Đây là một trong những thay đổi lớn nhất giữa 2 phiên bản.
  • Trong T-SQL, 10 / 3 cho 3 nếu cả hai là INT. Python 3 luôn cho số thực với /.

1.2. // — Chia lấy nguyên (làm tròn xuống)

print(17 // 5)         # 3
print(17.0 // 5)       # 3.0   <- float vào thì float ra
print(-17 // 5)        # -4    <- CHÚ Ý! làm tròn XUỐNG, không phải cắt bỏ

// gọi là floor division — làm tròn xuống dưới (về phía âm vô cực), khác với int() là cắt bỏ phần thập phân (về phía 0):

print(-17 / 5)         # -3.4
print(-17 // 5)        # -4     (làm tròn xuống)
print(int(-17 / 5))    # -3     (cắt bỏ)

1.3. % — Chia lấy dư

print(17 % 5)          # 2
print(10 % 2)          # 0     -> chia hết
print(11 % 2)          # 1     -> lẻ

Ứng dụng thực tế:

# Kiểm tra chẵn/lẻ
so = 24
print(so % 2 == 0)     # True -> số chẵn
 
# Kiểm tra chia hết
print(100 % 25 == 0)   # True
 
# Tách số
tong_giay = 7385
gio = tong_giay // 3600
con_lai = tong_giay % 3600
phut = con_lai // 60
giay = con_lai % 60
print(gio, "gio", phut, "phut", giay, "giay")   # 2 gio 3 phut 5 giay
 
# Tách chữ số hàng đơn vị
so = 12345
print(so % 10)         # 5
 
# Kiểm tra năm nhuận (một phần)
nam = 2024
print(nam % 4 == 0)    # True

1.4. ** — Lũy thừa

print(2 ** 10)         # 1024
print(2 ** 0.5)        # 1.4142135623730951 -> căn bậc hai
print(27 ** (1/3))     # 3.0000000000000004 -> căn bậc ba (có sai số float)
print(10 ** -2)        # 0.01

1.5. Toán tử với chuỗi

# + nối chuỗi (concatenation)
print("Ke" + " " + "toan")      # Ke toan
 
# * nhân bản chuỗi (repetition)
print("-" * 30)                 # ------------------------------
print("ab" * 3)                 # ababab
 
# CHỈ có 2 toán tử này hoạt động với chuỗi
print("abc" - "a")              # ❌ TypeError
print("abc" / 2)                # ❌ TypeError

Mẹo dùng * để vẽ đường kẻ trong báo cáo:

print("=" * 50)
print("BAO CAO DOANH THU THANG 08/2026")
print("=" * 50)

2. Toán tử gán (Assignment Operators)

Toán tửVí dụTương đương
=x = 5—
+=x += 3x = x + 3
-=x -= 3x = x - 3
*=x *= 3x = x * 3
/=x /= 3x = x / 3
//=x //= 3x = x // 3
%=x %= 3x = x % 3
**=x **= 3x = x ** 3
tong = 0
tong += 100        # tong = 100
tong += 250        # tong = 350
tong += 50         # tong = 400
print(tong)        # 400

Cách viết này gọi là augmented assignment (gán kết hợp), dùng rất nhiều trong vòng lặp ở 07 - Vòng lặp (for-while).

Áp dụng được cả với chuỗi:

ket_qua = ""
ket_qua += "Dong 1\n"
ket_qua += "Dong 2\n"
print(ket_qua)

Python KHÔNG có ++ và --

i++      # ❌ SyntaxError
i += 1   # ✅ Cách đúng

Nếu bạn từng thấy i++ trong C#, Java, JavaScript — Python cố tình bỏ toán tử này vì nó gây nhầm lẫn (i++ khác ++i).


3. Toán tử so sánh (Comparison Operators)

Toán tửÝ nghĩaVí dụKết quả
==Bằng5 == 5True
!=Khác5 != 3True
>Lớn hơn5 > 3True
<Nhỏ hơn5 < 3False
>=Lớn hơn hoặc bằng5 >= 5True
<=Nhỏ hơn hoặc bằng5 <= 3False

Kết quả của mọi phép so sánh luôn là True hoặc False.

tuoi = 25
print(tuoi >= 18)          # True
print(type(tuoi >= 18))    # <class 'bool'>

3.1. Bảng đối chiếu với SQL

SQLPython
= (so sánh)==
<> hoặc !=!=
IS NULLis None
IS NOT NULLis not None
BETWEEN 1 AND 101 <= x <= 10
IN ('A','B')x in ("A", "B")
NOT INx not in (...)
LIKE 'ABC%'x.startswith("ABC")

3.2. So sánh chuỗi

Chuỗi so sánh theo thứ tự Unicode code point, gần giống thứ tự từ điển:

print("apple" < "banana")    # True
print("Apple" < "apple")     # True  (chữ hoa có mã nhỏ hơn chữ thường)
print("a" == "A")            # False (phân biệt hoa thường)
print("10" < "9")            # True !!! so sánh CHUỖI ký tự đầu: "1" < "9"

Bẫy so sánh chuỗi chứa số

"10" < "9" cho True vì Python so sánh ký tự đầu tiên: "1" có mã nhỏ hơn "9". Đây là lỗi hay gặp khi quên ép kiểu dữ liệu từ input().

so = input("Nhap so: ")     # người dùng gõ 10
print(so > "9")             # True — sai về mặt số học!
print(int(so) > 9)          # True — đúng

So sánh không phân biệt hoa thường:

a = "Nguyen Van A"
b = "NGUYEN VAN A"
print(a == b)                    # False
print(a.lower() == b.lower())    # True

3.3. So sánh chuỗi (chaining) — đặc trưng của Python

tuoi = 25
 
# Python cho phép viết liên tiếp
print(18 <= tuoi <= 60)     # True
 
# Các ngôn ngữ khác phải viết
print(tuoi >= 18 and tuoi <= 60)    # True — dài hơn

Cách viết 18 <= tuoi <= 60 tương đương với BETWEEN 18 AND 60 trong SQL và là cách viết được khuyến khích trong Python.

diem = 8.5
print(0 <= diem <= 10)      # True — kiểm tra điểm hợp lệ

4. Toán tử logic (Logical Operators)

Toán tửSQL tương đươngÝ nghĩa
andANDCả hai đều đúng
orORÍt nhất một cái đúng
notNOTPhủ định

Python dùng chữ, không dùng ký hiệu

if a and b:      # ✅ Python
if a && b:       # ❌ SyntaxError — đây là C#/Java/JavaScript

4.1. Bảng chân trị

and:

ABA and B
TrueTrueTrue
TrueFalseFalse
FalseTrueFalse
FalseFalseFalse

or:

ABA or B
TrueTrueTrue
TrueFalseTrue
FalseTrueTrue
FalseFalseFalse

not:

Anot A
TrueFalse
FalseTrue

4.2. Ví dụ thực tế

tuoi = 25
co_bang_lai = True
da_uong_ruou = False
 
# Đủ điều kiện lái xe
print(tuoi >= 18 and co_bang_lai and not da_uong_ruou)   # True
 
# Xét duyệt hóa đơn
gia_tri_hd = 15_000_000
da_co_hop_dong = True
NGUONG_CAN_DUYET = 10_000_000
 
can_duyet = gia_tri_hd > NGUONG_CAN_DUYET or not da_co_hop_dong
print(can_duyet)     # True

4.3. ⚠️ Short-circuit evaluation (tính toán rút gọn)

Python dừng đánh giá ngay khi biết chắc kết quả:

  • Với and: nếu vế trái là False → không thèm xét vế phải (vì kết quả chắc chắn False)
  • Với or: nếu vế trái là True → không thèm xét vế phải (vì kết quả chắc chắn True)
# Vế phải sẽ gây lỗi chia cho 0, nhưng không bao giờ được chạy
so_luong = 0
print(so_luong > 0 and 100 / so_luong > 5)    # False — an toàn

Nếu không có short-circuit, 100 / 0 sẽ gây ZeroDivisionError. Đây là kỹ thuật bảo vệ rất hay dùng:

ten = None
 
# ❌ Lỗi
# print(len(ten) > 0)          # TypeError
 
# ✅ An toàn nhờ short-circuit
print(ten is not None and len(ten) > 0)      # False

4.4. and/or trả về GIÁ TRỊ, không phải chỉ True/False

Đây là điểm đặc biệt của Python mà nhiều người bất ngờ:

print(5 and 10)            # 10    <- không phải True
print(0 and 10)            # 0
print(5 or 10)             # 5
print(0 or 10)             # 10
print("" or "mac dinh")    # "mac dinh"
print(None or 0 or "cuoi") # "cuoi"

Quy tắc:

  • A and B: nếu A là falsy → trả về A; ngược lại trả về B
  • A or B: nếu A là truthy → trả về A; ngược lại trả về B

Ứng dụng — giá trị mặc định:

ten_nhap = input("Nhap ten (Enter de bo qua): ")
ten = ten_nhap or "Khach vang lai"
print("Xin chao,", ten)

Nếu người dùng nhấn Enter luôn, ten_nhap là "" (falsy) → ten nhận "Khach vang lai".

Tương đương với ISNULL() / COALESCE() trong SQL

SELECT ISNULL(@Ten, N'Khach vang lai')
ten = ten_nhap or "Khach vang lai"

Khác biệt: SQL ISNULL chỉ xét NULL, còn Python or xét mọi giá trị falsy (bao gồm 0 và ""). Cẩn thận với trường hợp giá trị hợp lệ là số 0:

so_luong = 0
kq = so_luong or 100      # kq = 100 — SAI Ý ĐỒ! 0 là giá trị hợp lệ
kq = so_luong if so_luong is not None else 100   # ĐÚNG

5. Toán tử đồng nhất và thành viên

5.1. is và is not — Identity Operators

== so sánh giá trị. is so sánh có phải cùng một đối tượng trong bộ nhớ không.

a = [1, 2, 3]
b = [1, 2, 3]
c = a
 
print(a == b)    # True  — cùng nội dung
print(a is b)    # False — hai đối tượng khác nhau trong bộ nhớ
print(a is c)    # True  — c chính là a

Chỉ dùng is với None, True, False

if x is None:        # ✅ ĐÚNG
if ten is "abc":     # ❌ SAI — dùng == cho chuỗi
if so is 1000:       # ❌ SAI — dùng == cho số

Python có cơ chế caching cho số nhỏ (-5 đến 256) và một số chuỗi ngắn, khiến is đôi khi cho True một cách tình cờ:

a = 100
b = 100
print(a is b)      # True — do caching
 
a = 1000
b = 1000
print(a is b)      # False (thường vậy) — không được cache

Kết quả không đáng tin cậy và có thể khác nhau giữa các phiên bản Python. Nguyên tắc: is chỉ dành cho None, True, False.

5.2. in và not in — Membership Operators

# Với chuỗi
print("toan" in "Ke toan")           # True
print("Toan" in "Ke toan")           # False — phân biệt hoa thường
 
# Với list
danh_sach = ["KH001", "KH002", "KH003"]
print("KH002" in danh_sach)          # True
print("KH999" not in danh_sach)      # True
 
# Với tuple
print("A" in ("A", "B", "C"))        # True

Đây chính là IN của SQL:

WHERE MaKH IN ('KH001', 'KH002', 'KH003')
if ma_kh in ("KH001", "KH002", "KH003"):
    ...

6. Độ ưu tiên toán tử (Operator Precedence)

Bảng từ ưu tiên cao nhất xuống thấp nhất:

MứcToán tửTên
1()Ngoặc tròn
2**Lũy thừa
3+x, -x, ~xDấu đơn nguyên
4*, /, //, %Nhân, chia
5+, -Cộng, trừ
6<, <=, >, >=, !=, ==So sánh
7in, not in, is, is notThành viên, đồng nhất
8notPhủ định
9andVà
10orHoặc

Ví dụ

print(2 + 3 * 4)          # 14  (nhân trước: 2 + 12)
print((2 + 3) * 4)        # 20  (ngoặc trước)
print(2 ** 3 ** 2)        # 512 (** kết hợp PHẢI sang TRÁI: 2^(3^2) = 2^9)
print((2 ** 3) ** 2)      # 64
print(-2 ** 2)            # -4  (** trước dấu âm: -(2^2))
print((-2) ** 2)          # 4
print(10 - 3 - 2)         # 5   (trừ kết hợp TRÁI sang PHẢI: (10-3)-2)
print(True or False and False)      # True  (and trước or)
print((True or False) and False)    # False

Quy tắc thực dụng

Đừng cố nhớ hết bảng này. Hãy dùng dấu ngoặc.

# ❌ Đúng nhưng khó đọc
if a > 5 and b < 10 or c == 0 and not d:
 
# ✅ Rõ ràng
if (a > 5 and b < 10) or (c == 0 and not d):

Dấu ngoặc không làm chậm chương trình, nhưng cứu bạn khỏi lỗi logic khó tìm.


7. Toán tử ba ngôi (Conditional Expression)

# Cú pháp: <giá trị nếu đúng> if <điều kiện> else <giá trị nếu sai>
 
tuoi = 20
loai = "Nguoi lon" if tuoi >= 18 else "Tre em"
print(loai)     # Nguoi lon

Tương đương với CASE WHEN trong SQL:

SELECT CASE WHEN Tuoi >= 18 THEN N'Nguoi lon' ELSE N'Tre em' END

Ví dụ khác:

so_luong = 150
gia_goc = 100000
gia_ban = gia_goc * 0.9 if so_luong >= 100 else gia_goc
print(gia_ban)      # 90000.0
 
# Tránh chia cho 0
tong = 0
so_ban_ghi = 0
trung_binh = tong / so_ban_ghi if so_ban_ghi > 0 else 0
print(trung_binh)   # 0

Chỉ dùng cho trường hợp đơn giản

Nếu logic có từ 3 nhánh trở lên, hãy dùng if/elif/else ở 06 - Cấu trúc rẽ nhánh (if-elif-else) cho dễ đọc.


8. Thực hành bắt buộc

Bài 1 — Dự đoán kết quả

Viết dự đoán ra giấy trước, rồi chạy đối chiếu:

print(15 / 4)
print(15 // 4)
print(15 % 4)
print(-15 // 4)
print(-15 % 4)
print(2 ** 3 ** 2)
print(-3 ** 2)
print(10 == 10.0)
print("10" == 10)
print(True + True + True)
print(5 and 0)
print(0 or "abc")
print(not 0)
print(1 < 2 < 3)
print(3 > 2 > 1 > 0)

Kết quả nào sai so với dự đoán? Ghi vào nhật ký kèm giải thích.

Bài 2 — Máy tính bỏ túi

Nhập 2 số, in ra tất cả kết quả của 7 phép toán số học.

Nhap so thu nhat: 17
Nhap so thu hai: 5
17 + 5 = 22
17 - 5 = 12
17 * 5 = 85
17 / 5 = 3.4
17 // 5 = 3
17 % 5 = 2
17 ** 5 = 1419857

Bài 3 — Kiểm tra số

Nhập một số nguyên, in ra (dạng True/False):

  • Số đó có chẵn không
  • Số đó có chia hết cho 3 không
  • Số đó có nằm trong khoảng 100–999 không (dùng chained comparison)
  • Số đó có phải số dương không

Bài 4 — Năm nhuận

Nhập một năm, dùng một biểu thức logic duy nhất để xác định có phải năm nhuận không.

Quy tắc: chia hết cho 4 và (không chia hết cho 100 hoặc chia hết cho 400).

nam = int(input("Nhap nam: "))
la_nam_nhuan = ...   # viết biểu thức ở đây
print(nam, "la nam nhuan:", la_nam_nhuan)

Kiểm tra: 2024 → True, 1900 → False, 2000 → True, 2026 → False

Bài 5 — Tách chữ số

Nhập một số có đúng 3 chữ số, in ra từng chữ số hàng trăm, hàng chục, hàng đơn vị. Dùng // và %.

Nhap so co 3 chu so: 456
Hang tram: 4
Hang chuc: 5
Hang don vi: 6
Tong cac chu so: 15

Bài 6 — Chiết khấu bậc thang (dùng toán tử ba ngôi)

Nhập tổng tiền hàng. Chiết khấu:

  • Từ 10 triệu trở lên: 10%
  • Dưới 10 triệu: 0%

In ra tiền chiết khấu và tiền phải trả. Dùng toán tử ba ngôi.

Bài 7 — Giải thích short-circuit

Giải thích vì sao đoạn code sau không báo lỗi, viết vào nhật ký:

ds = []
print(len(ds) > 0 and ds[0] == "abc")

9. Tự kiểm tra

  • Tôi phân biệt được /, //, % và biết -17 // 5 = -4
  • Tôi biết ** kết hợp từ phải sang trái
  • Tôi dùng and/or/not thay vì &&/||/!
  • Tôi hiểu short-circuit evaluation và biết ứng dụng để tránh lỗi
  • Tôi biết and/or trả về giá trị chứ không chỉ True/False
  • Tôi biết is chỉ dùng cho None/True/False
  • Tôi viết được chained comparison 0 <= x <= 100
  • Tôi biết dùng toán tử ba ngôi

10. Tài liệu chính thức

NguồnNội dungLink
ExpressionsToàn bộ biểu thức và toán tửhttps://docs.python.org/3/reference/expressions.html
Operator precedenceBảng độ ưu tiên đầy đủhttps://docs.python.org/3/reference/expressions.html#operator-precedence
Boolean Operationsand, or, nothttps://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not
ComparisonsToán tử so sánhhttps://docs.python.org/3/library/stdtypes.html#comparisons

Tiếp theo → 05 - Chuỗi ký tự (String)