Nhận biết lỗi chương trình Python – Lý thuyết, bài tập

I. Lý thuyết trọng tâm

1. Ba loại lỗi trong chương trình Python

Khi viết và chạy chương trình, lỗi có thể xuất hiện ở nhiều giai đoạn khác nhau. Python phân biệt ba loại lỗi chính, mỗi loại có biểu hiện và cách xử lý riêng.

a) Lỗi cú pháp (Syntax Error)

Xảy ra khi người lập trình viết lệnh sai quy tắc ngôn ngữ Python. Chương trình dừng ngay lập tức, chưa kịp chạy dòng nào, và hiển thị thông báo SyntaxError.

Ví dụ: Thiếu dấu hai chấm sau while True:

>>> while True print("Hello")
SyntaxError: invalid syntax

Nguyên nhân phổ biến: thiếu dấu :, thiếu ngoặc, sai từ khoá, viết sai tên lệnh.

b) Lỗi ngoại lệ (Runtime Error / Exceptions Error)

Xảy ra trong khi chương trình đang chạy, khi một lệnh nào đó không thể thực hiện được. Chương trình dừng lại giữa chừng và trả về mã lỗi ngoại lệ cụ thể.

Ví dụ 1 – ValueError: Nhập số thực nhưng hàm int() yêu cầu số nguyên:

>>> n = int(input("Nhập số nguyên n: "))
Nhập số nguyên n: 1.5
ValueError: invalid literal for int() with base 10: '1.5'

Ví dụ 2 – IndexError: Truy cập phần tử vượt quá kích thước danh sách:

A = [1, 3, 10, 0]
for i in range(5):      # A chỉ có 4 phần tử (chỉ số 0–3)
    print(A[i], end=" ")
# In được: 1 3 10 0 rồi báo lỗi
IndexError: list index out of range

c) Lỗi logic (Logical Error)

Chương trình chạy bình thường, không có thông báo lỗi nào, nhưng kết quả đưa ra sai so với yêu cầu bài toán. Đây là loại lỗi khó phát hiện nhất vì Python không cảnh báo.

Ví dụ: Tính tổng ba số nguyên dương đầu tiên ($1 + 2 + 3 = 6$):

>>> s = 0
>>> for i in range(3):
        s = s + i
>>> print(s)
3

Kết quả ra 3 thay vì 6, bởi range(3) sinh ra dãy $0, 1, 2$ chứ không phải $1, 2, 3$. Lệnh đúng phải là range(1, 4).

Câu hỏi vận dụng lý thuyết từ SGK:

Câu 1: Khi gõ sai cú pháp một lệnh, chương trình dừng lại và báo lỗi – đó là lỗi loại gì?

Đáp án: Lỗi cú pháp – Syntax Error.

Câu 2: Bài toán yêu cầu sắp xếp dãy [3, 1, 8, 10, 0] thành dãy tăng dần. Kết quả thu được là [1, 3, 8, 10, 0]. Chương trình có lỗi không? Nếu có thì thuộc loại gì?

Đáp án: Có lỗi. Dãy tăng dần đúng phải là [0, 1, 3, 8, 10], nhưng kết quả có phần tử 0 vẫn nằm cuối. Chương trình chạy không báo lỗi nhưng kết quả sai → đây là lỗi logic.

2. Các mã lỗi ngoại lệ thường gặp

Khi gặp lỗi ngoại lệ, Python trả về một mã lỗi cho biết nguyên nhân cụ thể. Dưới đây là các mã lỗi quan trọng cần nắm:

Mã lỗi Ý nghĩa Ví dụ điển hình
SyntaxError Viết sai cú pháp ngôn ngữ while True print("Hi") – thiếu dấu :
IndentationError Thụt dòng sai vị trí hoặc không thẳng hàng Lệnh trong if không thụt vào đúng cách
NameError Sử dụng tên biến hoặc hàm chưa được khai báo print(x) khi x chưa được định nghĩa
TypeError Sai kiểu dữ liệu trong phép toán hoặc truy cập A[1.5] – chỉ số không phải số nguyên; "10" * 3.5 – nhân xâu với số thực
ValueError Giá trị không phù hợp khi chuyển đổi kiểu int("abc") hoặc int("1.55")
IndexError Chỉ số vượt quá phạm vi danh sách Danh sách 4 phần tử mà truy cập A[4]
ZeroDivisionError Thực hiện phép chia cho $0$ 10 / 0

Câu hỏi vận dụng lý thuyết từ SGK:

Nêu mã lỗi ngoại lệ của mỗi lệnh sau:

Lệnh Mã lỗi Giải thích
A[1.5] TypeError Chỉ số danh sách phải là số nguyên, 1.5 là số thực
int("abc") ValueError Xâu "abc" không thể chuyển thành số nguyên
"10" * 3.5 TypeError Phép nhân xâu chỉ chấp nhận số nguyên, 3.5 là số thực
12 + x(10) NameError x chưa được khai báo là hàm hay biến nào

II. Hướng dẫn thực hành

Nhiệm vụ 1: Kiểm tra khả năng sinh lỗi khi nhập và tính toán

Yêu cầu: Viết chương trình nhập hai số nguyên m, n từ bàn phím (cách nhau bởi dấu cách). Đưa ra tổng, hiệu, thương của hai số. Kiểm tra các khả năng sinh lỗi.

s = input("Nhập hai số m, n cách nhau bởi dấu cách: ")
sline = s.split()
m, n = int(sline[0]), int(sline[1])
print("Tổng, hiệu, thương 2 số đã nhập là:", m + n, m - n, m / n)

Các khả năng sinh lỗi:

  • Nhập giá trị không phải số nguyên (ví dụ 3.5 hoặc abc) → ValueError tại lệnh int()
  • Không có dấu cách giữa hai số → split() chỉ tạo 1 phần tử, truy cập sline[1] gây IndexError
  • Số n nhập bằng 0 → phép m / n gây ZeroDivisionError

Nhiệm vụ 2: Kiểm tra khả năng sinh lỗi khi nhập danh sách

Yêu cầu: Viết chương trình nhập số tự nhiên n, sau đó nhập lần lượt n số nguyên đưa vào danh sách A. In danh sách ra màn hình. Kiểm tra khả năng sinh lỗi.

n = int(input("Nhập số tự nhiên n: "))
A = []
for k in range(n):
    num = int(input("Nhập số thứ " + str(k + 1) + ": "))
    A.append(num)
print("Dãy đã nhập:", A)

Các khả năng sinh lỗi:

  • Giá trị n nhập vào không phải số nguyên → ValueError tại dòng đầu tiên
  • Mỗi số hạng nhập vào không phải số nguyên → ValueError tại lệnh int() trong vòng lặp

III. Phương pháp giải các dạng bài tập

Dạng 1: Nhận biết lỗi và xác định mã lỗi từ đoạn lệnh cho sẵn

Phương pháp chung:

  • Đọc kỹ từng dòng lệnh, chạy thử “trong đầu” theo thứ tự.
  • Xác định dòng nào có thể gây lỗi → đối chiếu với bảng mã lỗi ngoại lệ.
  • Phân biệt: nếu lệnh viết sai cú pháp → SyntaxError; nếu lệnh đúng cú pháp nhưng không thực hiện được → lỗi ngoại lệ (kèm mã lỗi cụ thể); nếu chạy được nhưng kết quả sai → lỗi logic.
  • Chú ý đặc biệt: phạm vi chỉ số danh sách, kiểu dữ liệu của toán hạng, phép chia cho $0$.

Bài mẫu – Luyện tập 1:

Các lệnh sau có sinh lỗi không? Nếu có thì mã lỗi là gì?

a)

>>> A = [1, 3, 5, 10, 0]
>>> for k in range(1, len(A) + 1):
        print(A[k])

Lời giải:

Danh sách A có 5 phần tử, chỉ số hợp lệ từ $0$ đến $4$.

range(1, len(A) + 1) = range(1, 6)k nhận các giá trị $1, 2, 3, 4, 5$.

  • Khi $k = 1, 2, 3, 4$: in được A[1] = 3, A[2] = 5, A[3] = 10, A[4] = 0.
  • Khi $k = 5$: A[5] vượt quá chỉ số → IndexError.

b)

>>> s1, s2 = "101010", 1010101
>>> s = s1 + s2

Lời giải:

s1 có kiểu str (xâu kí tự), s2 có kiểu int (số nguyên).

Phép cộng + giữa xâu và số nguyên không thực hiện được → TypeError.

Dạng 2: Phân tích khả năng sinh lỗi ngoại lệ của chương trình

Phương pháp chung:

  • Xác định các lệnh “nhạy cảm” trong chương trình: lệnh nhập dữ liệu (input kết hợp int/float), phép chia, truy cập chỉ số danh sách.
  • Với mỗi lệnh, tự hỏi: “Dữ liệu nào khiến lệnh này thất bại?”
  • Liệt kê từng tình huống lỗi kèm mã lỗi tương ứng.
  • Đặc biệt chú ý: danh sách rỗng, số chia bằng $0$, dữ liệu nhập sai kiểu.

Bài mẫu – Luyện tập 2:

Để tính giá trị trung bình của danh sách số A, người lập trình dùng lệnh:

gttb = sum(A) / len(A)

Lệnh này có thể sinh lỗi ngoại lệ không? Nếu có thì là lỗi gì?

Lời giải:

Có thể sinh lỗi trong các trường hợp:

  • Nếu A là danh sách rỗng (A = []): len(A) = 0, phép chia cho $0$ → ZeroDivisionError.
  • Nếu A chứa phần tử không phải số (ví dụ A = [1, "abc", 3]): hàm sum() không cộng được → TypeError.

Dạng 3: Viết chương trình và kiểm tra khả năng sinh lỗi

Phương pháp chung:

  • Viết chương trình theo yêu cầu bài toán.
  • Sau khi viết xong, rà soát từng lệnh: đâu là điểm có thể xảy ra lỗi?
  • Thử chạy với các bộ dữ liệu “cực đoan”: giá trị $0$, giá trị âm, nhập sai kiểu, danh sách rỗng.
  • Ghi nhận từng khả năng sinh lỗi kèm mã lỗi cụ thể.

Bài mẫu 1 – Vận dụng 1:

Viết chương trình nhập số tự nhiên n từ bàn phím, đưa ra danh sách các ước số thực sự của n (tính cả $1$, không tính $n$). Kiểm tra các khả năng sinh lỗi.

Lời giải:

n = int(input("Nhập số tự nhiên n: "))
uoc = []
for i in range(1, n):
    if n % i == 0:
        uoc.append(i)
print("Các ước số thực sự của", n, "là:", uoc)

Các khả năng sinh lỗi:

  • Nhập giá trị không phải số nguyên (ví dụ 3.5, abc) → ValueError tại int()
  • Nhập $n = 0$: range(1, 0) không lặp lần nào, kết quả là danh sách rỗng (không lỗi ngoại lệ, nhưng cần xem xét ý nghĩa bài toán)
  • Nhập $n = 1$: range(1, 1) không lặp, danh sách rỗng (đúng vì $1$ không có ước thực sự khác)
  • Nhập số âm: range(1, n) với $n < 0$ không lặp, danh sách rỗng

Bài mẫu 2 – Vận dụng 2:

Viết chương trình nhỏ để khi chạy sẽ sinh mã lỗi NameError.

Lời giải:

print(x)

Biến x chưa được khai báo hay gán giá trị → Python không tìm thấy tên x → sinh lỗi NameError: name 'x' is not defined.

IV. Sơ đồ tư duy – Nhận biết lỗi chương trình

NHẬN BIẾT LỖI CHƯƠNG TRÌNH

  1. Lỗi cú pháp (Syntax Error)
    • 1.1. Viết sai quy tắc ngôn ngữ Python
    • 1.2. Chương trình dừng ngay, chưa chạy dòng nào
    • 1.3. Thông báo: SyntaxError
    • 1.4. Nguyên nhân: thiếu dấu :, thiếu ngoặc, sai từ khoá
  2. Lỗi ngoại lệ (Runtime / Exceptions Error)
    • 2.1. Xảy ra khi đang chạy, một lệnh không thực hiện được
    • 2.2. Chương trình dừng giữa chừng, trả mã lỗi cụ thể
    • 2.3. Các mã phổ biến: ValueError, IndexError, TypeError, NameError, ZeroDivisionError
  3. Lỗi logic (Logical Error)
    • 3.1. Chương trình chạy bình thường, không báo lỗi
    • 3.2. Kết quả đưa ra sai so với yêu cầu bài toán
    • 3.3. Khó phát hiện nhất, cần kiểm tra bằng dữ liệu thử
  4. Cách phân biệt nhanh
    • 4.1. Có thông báo SyntaxError → Lỗi cú pháp
    • 4.2. Có mã lỗi khác (ValueError, IndexError,…) → Lỗi ngoại lệ
    • 4.3. Không báo lỗi nhưng kết quả sai → Lỗi logic
Thầy Phạm Thành Danh

Thầy Phạm Thành Danh

(Người kiểm duyệt, ra đề)

Chức vụ: Trưởng ban biên soạn môn Tin Học THPT

Trình độ: Cử nhân Sư phạm Tin học, Chứng chỉ hạng II, Chứng chỉ Tin học, Ngoại ngữ B1

Kinh nghiệm: 8+ năm kinh nghiệm tại Trường THPT Thuận Hóa