Danh sách bài viết

Bài 6: Toán tử số học, so sánh và logic

Tổng hợp các nhóm toán tử trong Python 3.x: số học, so sánh, logic, gán mở rộng, identity và membership. Kèm operator precedence, chained comparison, short-circuit evaluation và bài tập nhỏ trên Colab.

24/05/2026
11 phút đọc
0 lượt xem
1

Mục tiêu bài học

Sau bài này, bạn sẽ:

  • Phân biệt được / (true division) và // (floor division) trong Python 3.x.
  • Biết thứ tự ưu tiên (operator precedence) của các nhóm toán tử và khi nào nên dùng dấu ngoặc.
  • Viết được biểu thức so sánh nối chuỗi như 0 < x < 10.
  • Hiểu cơ chế short-circuit của and / or.
  • Dùng đúng is None thay vì == None.
  • Kiểm tra phần tử bằng in / not in.
2

Toán tử số học

Python 3.x có 7 toán tử số học cơ bản:

Toán tử Tên gọi Ví dụ Kết quả
+Cộng7 + 29
-Trừ7 - 25
*Nhân7 * 214
/True division7 / 23.5 (float)
//Floor division7 // 23 (int)
%Modulo (lấy dư)7 % 21
**Lũy thừa7 ** 249

Phân biệt ///

Đây là khác biệt quan trọng giữa Python 2 và Python 3. Trong Python 3.x, / luôn trả về float, kể cả khi cả hai toán hạng đều là int:

# True division: luôn trả về float
print(10 / 4)    # 2.5
print(8 / 2)     # 4.0  (không phải 4!)
print(type(8 / 2))  # <class 'float'>

# Floor division: làm tròn xuống số nguyên gần nhất
print(10 // 4)   # 2
print(8 // 2)    # 4
print(type(8 // 2))  # <class 'int'>

Lưu ý floor division // làm tròn về phía âm vô cùng, không phải về 0:

print(-7 // 2)   # -4  (không phải -3)
print(-7 / 2)    # -3.5

Modulo và lũy thừa

# Modulo: lấy phần dư của phép chia nguyên
print(17 % 5)    # 2  (17 = 3*5 + 2)
print(10 % 2)    # 0  → 10 là số chẵn

# Lũy thừa: a ** b = a^b
print(2 ** 10)   # 1024
print(2 ** 0.5)  # 1.4142135623730951 (căn bậc 2 của 2)

Toán tử % hay được dùng để kiểm tra chẵn lẻ hoặc chia batch dữ liệu sau này. ** hay xuất hiện trong công thức xác suất, neural network (ví dụ x ** 2 trong MSE loss).

3

Operator precedence và dấu ngoặc

Khi một biểu thức có nhiều toán tử, Python tính theo thứ tự ưu tiên (precedence). Bảng dưới liệt kê các nhóm hay gặp, từ ưu tiên cao đến thấp:

Hạng Toán tử Mô tả
1(...)Dấu ngoặc — ưu tiên cao nhất
2**Lũy thừa (kết hợp phải sang trái)
3+x, -xUnary plus / minus
4*, /, //, %Nhân, chia, chia nguyên, modulo
5+, -Cộng, trừ
6==, !=, <, >, <=, >=, is, inSo sánh, identity, membership
7notPhủ định logic
8andVà logic
9orHoặc logic

Ví dụ:

# Nhân được tính trước cộng
print(2 + 3 * 4)        # 14, không phải 20

# Dùng dấu ngoặc để đổi thứ tự
print((2 + 3) * 4)      # 20

# Lũy thừa kết hợp phải sang trái
print(2 ** 3 ** 2)      # 512  (= 2 ** (3 ** 2) = 2 ** 9)
print((2 ** 3) ** 2)    # 64   (= 8 ** 2)

Quy tắc thực dụng: khi không chắc, đặt dấu ngoặc. Code đọc rõ ràng quan trọng hơn việc tiết kiệm 2 ký tự.

Bảng đầy đủ về precedence ở mục Operator precedence trong Python Language Reference (xem phần sources).

4

Toán tử so sánh và chained comparison

Toán tử so sánh trả về kiểu bool (True hoặc False):

Toán tử Ý nghĩa Ví dụ
==Bằng giá trị3 == 3True
!=Khác giá trị3 != 4True
<Nhỏ hơn3 < 4True
>Lớn hơn3 > 4False
<=Nhỏ hơn hoặc bằng3 <= 3True
>=Lớn hơn hoặc bằng3 >= 4False
x = 5

print(x == 5)    # True
print(x != 10)   # True
print(x >= 5)    # True

# So sánh cũng dùng được với string (theo thứ tự lexicographic)
print("apple" < "banana")  # True

Chained comparison

Python cho phép nối nhiều phép so sánh trong một biểu thức, ngắn gọn và đọc gần như toán học:

x = 7

# Kiểm tra x nằm trong khoảng (0, 10)
print(0 < x < 10)    # True

# Tương đương với:
print(0 < x and x < 10)  # True

# Có thể nối nhiều hơn
score = 75
print(0 <= score <= 100)  # True

Lưu ý: chained comparison đánh giá biến ở giữa chỉ một lần. Đây là ưu điểm so với viết 0 < f(x) and f(x) < 10 (gọi f hai lần).

5

Toán tử logic và short-circuit

Python có 3 toán tử logic dạng từ khóa: and, or, not.

Biểu thức Kết quả
True and TrueTrue
True and FalseFalse
True or FalseTrue
False or FalseFalse
not TrueFalse
not FalseTrue
age = 25
has_id = True

# Kết hợp điều kiện
print(age >= 18 and has_id)  # True
print(age < 18 or has_id)    # True
print(not has_id)            # False

Short-circuit evaluation

Cả andor đánh giá lười (lazy): chỉ tính toán hạng bên phải khi cần.

  • A and B: nếu A là falsy, trả về luôn A, không đánh giá B.
  • A or B: nếu A là truthy, trả về luôn A, không đánh giá B.
# Tránh chia cho 0 nhờ short-circuit
x = 0
if x != 0 and 10 / x > 1:
    print("ok")
# Không lỗi vì vế phải không được đánh giá khi x == 0

# Đặt giá trị mặc định bằng or
name = ""
display = name or "Anonymous"
print(display)   # Anonymous

Lưu ý nhỏ: and / or trả về một trong hai toán hạng (không phải lúc nào cũng là True / False):

print(0 or "hello")   # "hello"
print(1 and "hello")  # "hello"
print(0 and "hello")  # 0
6

Toán tử gán mở rộng

Toán tử gán mở rộng (augmented assignment) là cách viết ngắn cho biểu thức kiểu x = x <op> y:

Viết tắt Tương đương
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
total = 0
total += 10        # total = 10
total += 5         # total = 15
total *= 2         # total = 30
total //= 4        # total = 7
print(total)       # 7

Augmented assignment hay xuất hiện khi cộng dồn loss, đếm số sample, hoặc cập nhật trọng số trong training loop.

Python không có ++ hay -- như C / JavaScript. Muốn tăng 1, dùng x += 1.

7

Identity: is / is not vs ==

Có hai khái niệm dễ nhầm:

  • == so sánh giá trị (equality).
  • is so sánh identity — hai biến có cùng tham chiếu đến một object trong bộ nhớ hay không (tương đương id(a) == id(b)).
a = [1, 2, 3]
b = [1, 2, 3]
c = a

print(a == b)   # True  (cùng giá trị)
print(a is b)   # False (hai object khác nhau)
print(a is c)   # True  (cùng object)

Khi nào dùng is?

Theo PEP 8, dùng is / is not khi so sánh với các singleton (object duy nhất) như None, True, False:

value = None

# Đúng chuẩn PEP 8
if value is None:
    print("không có giá trị")

if value is not None:
    print("có giá trị")

# Tránh viết: if value == None
# Lý do: == có thể bị class tự định nghĩa __eq__ ghi đè,
# trong khi None luôn là singleton duy nhất.

Cảnh báo: is với int nhỏ hoặc string ngắn đôi khi trả về True do CPython caching (ví dụ a = 256; b = 256; a is b). Đừng dựa vào hành vi này — luôn dùng == để so sánh giá trị.

8

Membership: in / not in

in kiểm tra một phần tử có thuộc một tập hợp (sequence / container) hay không, trả về bool. not in là phủ định.

# Với string: kiểm tra substring
print("py" in "python")        # True
print("java" not in "python")  # True

# Với list
fruits = ["apple", "banana", "cherry"]
print("apple" in fruits)       # True
print("mango" not in fruits)   # True

# Với dict: chỉ kiểm tra trên KEYS, không phải values
ages = {"An": 25, "Bình": 30}
print("An" in ages)            # True
print(25 in ages)              # False  (25 là value, không phải key)

Đây mới là cái nhìn xem trước (preview). Chi tiết về list, tuple, dict, set sẽ học từ Bài 11 trở đi. Hiện tại chỉ cần nhớ: in trả về bool và dùng được với mọi container.

9

Bài tập thực hành

Mở Google Colab (đã làm quen ở Bài 3) và thử các bài sau. Mục tiêu là tự gõ tay, đoán kết quả trước khi chạy, rồi đối chiếu.

Bài 1: Phân biệt ///

Cho hai số a = 23, b = 4. Viết code in ra:

  1. Thương đầy đủ (a / b)
  2. Phần nguyên của thương (a // b)
  3. Phần dư (a % b)
  4. Kiểm tra đẳng thức: a == (a // b) * b + (a % b) phải trả về True.

Bài 2: Kiểm tra điểm hợp lệ

Cho biến score nhận từ input(). Dùng chained comparison để in ra True nếu 0 <= score <= 10, ngược lại in False. Gợi ý: nhớ convert input() sang float.

Bài 3: Năm nhuận

Một năm được coi là nhuận nếu: chia hết cho 4 (không chia hết cho 100 hoặc chia hết cho 400). Viết biểu thức bool tính giá trị is_leap cho biến year bất kỳ, sử dụng %, and, or, not. Test với 2000 (True), 1900 (False), 2024 (True), 2023 (False).

10

Tổng kết

  • Số học: + - * / // % **. Nhớ / trả về float, // trả về int trong Python 3.x.
  • Precedence: lũy thừa > nhân chia > cộng trừ > so sánh > not > and > or. Dùng dấu ngoặc khi nghi ngờ.
  • So sánh trả về bool; có thể nối chuỗi như 0 < x < 10.
  • Logic and / or có short-circuit — hữu ích để tránh lỗi runtime và đặt giá trị mặc định.
  • Gán mở rộng += -= *= /= //= %= **= rút gọn cập nhật biến.
  • Dùng is / is not với None / True / False; còn lại dùng ==.
  • in / not in kiểm tra membership cho string, list, dict (theo key) và mọi container.

Bài tiếp theo sẽ dùng các biểu thức bool xây dựng được ở đây để rẽ nhánh chương trình bằng if / elif / else.