Bài 9. Xử lý lỗi

Lỗi là chuyện bình thường. Biết đọc thông báo lỗi và xử lý ngoại lệ giúp chương trình bền vững hơn.

30 phútCơ bản
Bạn sẽ học được
  • Đọc hiểu thông báo lỗi (traceback)
  • Phân biệt lỗi cú pháp, lỗi chạy, lỗi logic
  • Dùng try/except/else/finally
  • Chủ động báo lỗi bằng raise
Thuật ngữ cần biết
Ngoại lệ (exception)
Lỗi xảy ra khi chương trình đang chạy, ví dụ chia cho 0.
Traceback
Bản ghi các dòng mã dẫn tới lỗi; đọc từ dưới lên.
Gỡ lỗi (debug)
Quá trình tìm và sửa lỗi.
Lỗi logic
Chương trình chạy được nhưng cho kết quả sai.

Khái niệm và lý thuyết

Có ba nhóm lỗi: lỗi cú pháp (viết sai quy tắc, chương trình không chạy được), lỗi thời gian chạy (chạy được nhưng gặp tình huống không xử lý nổi, ví dụ chia cho 0) và lỗi logic (chạy trơn tru nhưng kết quả sai). Lỗi logic khó nhất vì máy không báo gì.

Khi lỗi thời gian chạy xảy ra, Python tạo một ngoại lệ (exception). Nếu không ai xử lý, chương trình dừng và in traceback, danh sách các lời gọi hàm dẫn đến lỗi. Cách đọc: dòng cuối cho biết loại lỗi và lý do, các dòng trên cho biết lỗi nằm ở tệp, dòng nào.

Cấu trúc try/except cho phép chương trình "bắt" ngoại lệ và xử lý thay vì sập. Nguyên tắc: chỉ bắt những lỗi bạn dự đoán được và biết cách xử lý (người dùng nhập sai, tệp không tồn tại), còn lỗi lập trình thì nên để lộ ra để sửa. Khối finally luôn chạy, dùng để dọn dẹp như đóng tệp, kết nối.

Các loại lỗi thường gặp

LỗiNguyên nhân thường gặp
SyntaxErrorSai cú pháp: thiếu dấu hai chấm, ngoặc
NameErrorDùng biến chưa khai báo hoặc gõ sai tên
TypeErrorPhép toán sai kiểu, như "5" + 3
ValueErrorGiá trị không hợp lệ: int("abc")
ZeroDivisionErrorChia cho 0
FileNotFoundErrorTệp không tồn tại
IndexError, KeyErrorChỉ số, khóa không có

Cách đọc traceback: nhìn dòng cuối cùng để biết loại lỗi và lý do, rồi xem số dòng ngay phía trên để biết lỗi ở đâu.

try / except

try:
    n = int(input("Nhập số: "))
    print(10 / n)
except ValueError:
    print("Bạn phải nhập số nguyên")
except ZeroDivisionError:
    print("Không chia được cho 0")
else:
    print("Không có lỗi")
finally:
    print("Luôn chạy, dùng để dọn dẹp")

Chủ động báo lỗi

def tinh_tuoi(nam_sinh):
    if nam_sinh > 2026:
        raise ValueError("Năm sinh không hợp lệ")
    return 2026 - nam_sinh

Ví dụ: chương trình không chết khi người dùng nhập sai

while True:
    try:
        tuoi = int(input("Nhập tuổi: "))
        break
    except ValueError:
        print("Vui lòng nhập số nguyên, ví dụ 25.")

Nếu người dùng gõ "hai mươi", Python sinh lỗi ValueError; khối except bắt lỗi, nhắc nhẹ nhàng rồi yêu cầu nhập lại thay vì dừng chương trình. Khi gặp lỗi, đừng hoảng: đọc dòng cuối cùng của thông báo lỗi, nó cho biết loại lỗi, và dòng ngay trên đó chỉ ra dòng mã gây lỗi.

Cách tìm lỗi logic

In giá trị trung gian bằng print, kiểm tra từng bước với ví dụ nhỏ, hoặc dùng trình gỡ lỗi của VS Code (đặt điểm dừng, bấm F5, xem giá trị biến).

Tình huống: Nhập số bắt buộc

Chương trình hỏi tuổi; người dùng gõ "hai mươi". Thay vì sập, ta hỏi lại đến khi hợp lệ:

while True:
    try:
        tuoi = int(input("Tuổi: "))
        break
    except ValueError:
        print("Vui lòng nhập số, ví dụ 20")
Mẹo hay

Chỉ bắt đúng loại lỗi bạn dự đoán. Tránh except: trống vì nó giấu cả lỗi bạn không ngờ tới.

Lưu ý

Đừng dùng try để che lỗi logic. Hãy sửa nguyên nhân thay vì bỏ qua.

Thực hành
  1. Viết hàm chia hai số an toàn, trả thông báo khi chia cho 0.
  2. Mở tệp do người dùng nhập tên; nếu không có thì báo.
  3. Cố tình tạo 5 loại lỗi trong bảng trên và đọc traceback của từng loại.
Tóm tắt bài học
  • Lỗi phổ biến: SyntaxError, NameError, TypeError, ValueError.
  • Đọc traceback từ dòng cuối.
  • try/except xử lý lỗi dự đoán được.
  • raise báo lỗi khi dữ liệu sai.