Tư duy Tính toán

Rẽ nhánh & Luồng điều khiển

Trường ĐH Công nghệ – Đại học Quốc gia Hà Nội

Nội dung

  1. Rẽ nhánh cơ bản
  2. Rẽ nhánh lồng nhau
  3. Truy vết lỗi
  4. Kiểm thử
  5. Giới thiệu sơ lược về hàm

1.
Rẽ nhánh
cơ bản

Luồng chương trình

Chương trình đơn giản: Các lệnh chạy cố định thứ tự qua mỗi lần chạy.

program flow in Scratch
Tiến lên Tiến lên Quay trái Tiến lên Tiến lên

Nhu cầu rẽ nhánh

Thực tế: Ta cần lựa chọn dựa trên dữ liệu vào.

Nếu đang ở vị trí hoa thì hút mật, ngược lại làm mật.

bee if in Scratch
Ở vị trí hoa Lấy mật Làm mật Đúng Sai

Câu lệnh if trong Python

Cú pháp


if <biểu-thức-Boolean>:
    <câu-lệnh-1>
    <câu-lệnh-2>
    ...
    <câu-lệnh-n>
        
  • Nếu <biểu-thức-Boolean> đúng (True):
    • Thực hiện tất cả các <câu-lệnh-i> trong khối lệnh.
  • Ngược lại: Bỏ qua khối lệnh.

Câu lệnh if: Ví dụ

Nếu x chẵn thì in even, ngược lại không làm gì.


x = 10
if x % 2 == 0:
    print('even')
        
x là số chẵn In ra 'even' Đúng Sai

Ví dụ về giá trị Boolean

Khai báo các biến:


is_rainy = False  # Giá trị kiểu Boolean
is_windy = True   # Giá trị kiểu Boolean
temp = 12         # Giá trị kiểu số nguyên
        

Biến Boolean:


if is_rainy:
    print("Hãy mang ô!")
        

Ví dụ về giá trị Boolean

Phép toán Boolean:


if is_windy and not is_rainy:
    print("Đi thả diều nào!")
        

Toán tử so sánh:


if temp < 10 and is_rainy:
    print("Hãy mặc áo khoác chống thấm nước!")

if temp >= 30:
    print("Uống nhiều nước!")
        

Câu lệnh ifelse

Cú pháp:


if <biểu-thức-Boolean>:
    <câu-lệnh>
    ...
else:
    <câu-lệnh>
    ...
        

Ví dụ:


if x % 2 == 0:
    print('even')
else:
    print('odd')
        
x là số chẵn In ra "even" In ra "odd" Đúng Sai

Cấu trúc vs. Luồng chương trình

Cấu trúc chương trình Luồng chương trình
Định nghĩa Cách mã được trình bày trong tệp. Thứ tự thực thi lệnh khi chạy.
Thứ tự / Nhánh Thứ tự dòng, mức thụt lề. Không trùng với cấu trúc; có thể bỏ qua nhánh.
Phạm vi Định nghĩa các khả năng qua nhiều lần chạy. Định nghĩa điều gì xảy ra trong một lần chạy.

Cấu trúc


# odd_even.py
x = 10
if x % 2 == 0:
    print("even")
else:
    print("odd")
      

print("odd") xuất hiện trong cấu trúc chương trình.

Luồng


$ python odd_even.py
even
      

Luồng chạy khiến print("odd") được thực thi 0 lần.

Tác động của if tới luồng

  • Điểm rẽ → đánh giá điều kiện, chọn nhánh.
  • Mỗi lần chạy chỉ đi một đường → có phần sẽ không được thực thi.
x là số chẵn In ra "even" In ra "odd" Đúng Sai Điểm rẽ
Lưu đồ (Flowchart) minh họa đường đi của chương trình.

Luồng chương trình & Biến


a = 0
if a == 0:
    b = a + 1   # b được tạo ở đây nếu nhánh này chạy
print(b)        # b vẫn tồn tại sau if nếu đã được gán
        

Biến được tạo chỉ khi lệnh gán tương ứng thực sự được thực thi.

Nhiều lựa chọn

  • Ví dụ: Xếp loại học lực dựa trên điểm số:
    • 90-100: Xuất sắc
    • 70-89: Giỏi
    • 50-69: Đạt
    • Dưới 50: Trượt
Điểm ≥ 90 Điểm ≥ 70 Điểm ≥ 50 Xuất sắc Giỏi Đạt Trượt Đúng Sai Đúng Sai Đúng Sai

ifelifelse

Cú pháp

if <biểu-thức>:
    <câu-lệnh>
    ...
elif <biểu-thức>:
    <câu-lệnh>
    ...
elif <biểu-thức>:
    <câu-lệnh>
    ...
else:
    <câu-lệnh>
    ...
        
Ví dụ

score = 80

if score >= 90:
    print("Excellent!")
elif score >= 70:
    print("Good job!")
elif score >= 50:
    print("Pass.")
else:
    print("Fail.")
        

Lưu ý khi dùng elif

  • if chỉ xuất hiện một lần ở đầu chuỗi.
  • elif không giới hạn số lượng, chỉ ở giữa ifelse.
  • elsetùy chọn: Không bắt buộc phải có.
  • Điều kiện được kiểm tra theo thứ tự:
    • Gặp điều kiện đúng thì bỏ qua phần sau.
    • else tương đương: Tất cả điều kiện đều sai.

Nhiều if


x = 0
if x == 0:
    print("x is 0!")
if x == 0:
    print("still 0!")
if x == 0:
    print("even still 0")
            
Kết quả:

x is 0!
still 0!
even still 0
              

if–elif


x = 0
if x == 0:
    print("x is 0!")
elif x == 0:
    print("still 0!")
elif x == 0:
    print("even still 0")
            
Kết quả:

x is 0!
              

Chuỗi if & elif đảm bảo chỉ một nhánh được chọn.

2.
Rẽ nhánh
lồng nhau

Logic có thể phức tạp hơn


if raining and freezing:
    print('Wear a waterproof coat.')
elif raining and not freezing:
    print('Bring an umbrella.')
elif not raining and freezing:
    print('Wear a warm coat!')
else:
    print('A sweater will suffice.')
      
raining False freezing False ... sweater True ... warm coat True freezing False ... umbrella True ... waterproof coat

Điều kiện lồng nhau


if raining:
    if freezing:
        print('Wear a waterproof coat.')
    else:
        print('Bring an umbrella.')
else:
    if freezing:
        print('Wear a warm coat!')
    else:
        print('A sweater will suffice.')
      
raining False freezing False ... sweater True ... warm coat True freezing False ... umbrella True ... waterproof coat

3.
Truy vết lỗi

Gỡ lỗi (Debugging)

  • Mục tiêu: xác định và sửa lỗi.
  • Công cụ: Debugger (breakpoint/step/watch), Logging (levels), Tests/Assertions.
  • Quy trình: tái hiện lỗi → giả thuyết → thử nhanh → sửa → thêm test.
  • Dùng print(): kiểm tra nhanh, đoạn mã nhỏ.
  • Tránh print(): hệ thống lớn → ưu tiên debugger + logging.

Dùng print() để truy vết


# determine winner
if x_score > y_score:
    winner = "x"
else:
    winner = "y"
      

Có thể dùng print() để truy vết luồng chương trình và theo dõi giá trị biến:

  • Đặt print() tại đầu khối để biết khối có chạy không.
  • Đặt print() sau khi gán để xem giá trị.

Dùng print() để truy vết

Truy vết (Trace) = in ra “dấu vết”.


# determine winner
print('before if')        # TRACE: truy vết vị trí trước if
if x_score > y_score:
    print('inside if')    # TRACE: truy vết vị trí trong if
    winner = "x"
else:
    print('inside else')  # TRACE: truy vết vị trí trong else
    winner = "y"
print('after if')
      

Kết quả mẫu:


before if
inside if
after if
      

Từ dấu vết trên, suy ra: x_score > y_score.

Truy vết (Trace) VS. Theo dõi (Watch)


# determine winner
print('before if')              # TRACE: truy vết vị trí trước if

if x_score > y_score:
    print('inside if')          # TRACE: truy vết vị trí trong if
    winner = "x"
    print('winner =', winner)   # WATCH: xem giá trị winner
else:
    print('inside else')        # TRACE: truy vết vị trí trong else
    winner = "y"
    print('winner =', winner)   # WATCH: xem giá trị winner

print('after if')               # TRACE: truy vết vị trí sau if
      
  • TRACE: truy vết luồng — đặt ở đầu khối có thể bị bỏ qua.
  • WATCH: theo dõi dữ liệu — đặt sau lệnh gán để xem giá trị biến.

→ Dùng cả 2 để biết khối nào chạybiến đang mang giá trị gì.

4.
Kiểm thử

Kiểm thử là gì?

Kiểm thử = chạy chương trình với dữ liệu cụ thể để:

  • Quan sát kết quả thực tế
  • So sánh với kết quả mong đợi
  • Phát hiện sự khác biệt (nếu có)

Tại sao cần kiểm thử?

  • Phát hiện lỗi trước khi chương trình chạy sai trong thực tế.
  • Xác nhận chương trình làm đúng như mong đợi.
  • Bảo trì dễ dàng khi thay đổi mã nguồn.
  • Tự tin hơn khi phát triển tính năng mới.

Quy tắc kiểm thử 1–2–0

  • 1 — Base (happy path): kịch bản phổ biến nhất, xác minh logic cốt lõi.
  • 2 — Boundary:Thử ở ranh giới nơi lỗi dễ xuất hiện.
    • Tại ranh giới hợp lệ (ví dụ: tại min/max)
    • Ngay ngoài phạm vi hợp lệ (ví dụ: min−1 hoặc max+1)
  • 0 — Outliers: tạm bỏ qua các trường hợp hiếm/không hợp lệ; bổ sung sau nếu cần.

Mục tiêu: bao phủ nhanh, bắt lỗi ngưỡng, tối ưu công sức.

Ví dụ 1–2–0

Quy tắc: Trả bình thường ≤ 40h; phần vượt 40h trả 1.5×.


def weekly_pay(hours, rate):
    if hours <= 40:
        return hours * rate
    overtime = hours - 40
    return 40 * rate + overtime * rate * 1.5
  • 1 — Base: weekly_pay(36, 20) == 720
  • 2 — Boundary:
    • Tại ngưỡng: weekly_pay(40, 20) == 800
    • Ngay ngoài: weekly_pay(41, 20) == 830
  • 0 — Outliers: bỏ qua (giờ âm/không số, rate 0, cực lớn...).

Với if, cần thêm gì?

  • Tạo đủ ca kiểm thử để mọi nhánh trong ifelifelse được chạy.
  • Tương tự với các lệnh if lồng nhau.

Kiểm thử câu lệnh if


if score >= 90:
    print("Excellent!")
elif score >= 70:
    print("Good job!")
elif score >= 50:
    print("Pass.")
else:
    print("Fail.")
      

Thiết kế test: 4 ca, mỗi ca dẫn đến một nhánh khác nhau.

Ví dụ: 91, 80, 55, 40.

Kiểm thử if lồng nhau


if raining:
    if freezing:
        print('Wear a waterproof coat.')
    else:
        print('Bring an umbrella.')
else:
    if freezing:
        print('Wear a warm coat!')
    else:
        print('A sweater will suffice.')
      

Thiết kế test: 4 ca tương ứng mọi kết hợp:
(raining, freezing) =
(True, True), (True, False),
(False, True), (False, False).

Hai kiểu Kiểm thử

Hộp đen (Black Box)

  • Không biết nội dung hàm.
  • Tạo ca kiểm thử dựa chỉ vào đặc tả chương trình.

Hộp kính (Glass Box)

  • Biết nội dung hàm.
  • Tạo ca kiểm thử dựa cả đặc tả lẫn mã nguồn.

5.
Sơ lược về hàm

Một chút về hàm

Bạn có nhớ trò chơi Scratch nho nhỏ này?

Scratch function blocks

def move_forward():
    print("move forward")

def turn_left():
    print("turn_left")

move_forward()
move_forward()
turn_left()
move_forward()
move_forward()
        
  • Scratch có sẵn lệnh move forward, turn left.
  • Python chưa có → ta tự định nghĩa, được gọi là hàm.

Định nghĩa & Gọi hàm

Định nghĩa hàm


def move_forward():
    print("move forward")

def turn_left():
    print("turn_left")
        

Gọi hàm


move_forward()
move_forward()
turn_left()
move_forward()
move_forward()
        

Kết quả: Mỗi lần gọi hàm sẽ thực thi khối lệnh bên trong hàm đó.


move forward
move forward
turn_left
move forward
move forward
        

Hàm với tham số

Tham số: giá trị truyền vào hàm khi gọi.


def what_to_wear(raining, freezing):
    if raining:
        if freezing:
            # ... truncated
    else:
        if freezing:
            # ... truncated
    

Hàm what_to_wear có hai tham số: rainingfreezing.


what_to_wear(True, False)
what_to_wear(True, True)
what_to_wear(False, False)
what_to_wear(raining=False, freezing=True)
    

Hàm trả về giá trị

  • Dùng return để trả về kết quả từ hàm.
  • Thường dùng để tính toán rồi gán cho biến.

def what_to_wear(raining, freezing):
    if raining:
        if freezing:
            return "Waterproof coat"
        else:
            return "Umbrella"
    else:
        if freezing:
            return "Warm coat"
        else:
            return "Sweater"

today_outfit = what_to_wear(True, False)
sunny_day_outfit = what_to_wear(False, False)
  

Gọi hàm trong module

Module = tập hợp hàm (và biến) trong một file .py.


# sample_functions.py
def what_to_wear(raining, freezing):
    if raining:
        if freezing:
            return "Waterproof coat"
        else:
            return "Umbrella"
    else:
        # ... truncated
    

Dùng import để nhập module vào chương trình.


from sample_functions import what_to_wear

today_outfit = what_to_wear(True, False)
    

Gọi hàm trong Interactive Shell

  • Gõ lệnh và xem kết quả ngay
  • Thử nhanh hàm hoặc đoạn mã nhỏ
  • Cách dùng:python trong terminal

$ python
Python 3.13.7 | packaged by conda-forge | (main, Sep  3 2025, 14:33:26) [Clang 19.1.7 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
 
  • Giao diện: Nhập hàm từ module rồi gọi

>>> from sample_functions import what_to_wear
>>> print_what_to_wear(True, False)
Wear a waterproof coat.
    

Một chút về hàm: Tổng kết

  • Hàm là những khối để xây nên chương trình.
  • Chúng ta sẽ sử dụng hàm rất nhiều từ bây giờ.
  • Sẽ học sâu hơn về hàm trong các bài sau.

Tổng kết

  1. Rẽ nhánh với if, elif, else
  2. Rẽ nhánh lồng nhau
  3. Truy vết lỗi với print()
  4. Kiểm thử để đảm bảo mọi nhánh đều chạy
  5. Một chút về hàm: định nghĩa, tham số, trả về giá trị, gọi hàm trong module và interactive shell