Xử lý lỗi¶
I. Lý thuyết¶
1. Định nghĩa¶
Xử lý lỗi (Exception Handling) là cơ chế cho phép chương trình xử lý các tình huống bất thường mà không bị dừng đột ngột. Python sử dụng cấu trúc try-except
để bắt và xử lý các lỗi có thể xảy ra trong quá trình thực thi chương trình.
2. Đặc điểm của xử lý lỗi¶
- Giúp chương trình không bị crash khi gặp lỗi.
- Cho phép xử lý linh hoạt các tình huống bất thường.
- Cung cấp thông báo lỗi có ý nghĩa cho người dùng.
- Tăng tính ổn định và trải nghiệm người dùng.
3. Cú pháp cơ bản¶
try:
# Khối lệnh có thể gây ra lỗi
pass
except TenLoiCuThe:
# Xử lý khi gặp lỗi cụ thể
pass
except:
# Xử lý tất cả các lỗi khác
pass
else:
# Thực thi khi không có lỗi (tùy chọn)
pass
finally:
# Luôn thực thi (tùy chọn)
pass
Từ khóa raise
được sử dụng để tạo ra lỗi một cách chủ động trong chương trình. Thay vì chờ lỗi xảy ra tự nhiên, chúng ta có thể tự tạo ra lỗi khi phát hiện điều kiện không mong muốn.
# Cú pháp cơ bản
raise TenLoiCuThe("Thông điệp lỗi")
4. Các loại lỗi thường gặp¶
Tên lỗi | Mô tả | Ví dụ |
---|---|---|
ValueError |
Giá trị không đúng kiểu | int("abc") |
ZeroDivisionError |
Chia cho 0 | 10 / 0 |
IndexError |
Chỉ số vượt quá phạm vi | [1,2][5] |
KeyError |
Key không tồn tại trong dict | {"a": 1}["b"] |
FileNotFoundError |
File không tồn tại | open("file_khong_ton_tai.txt") |
TypeError |
Kiểu dữ liệu không phù hợp | "abc" + 5 |
II. Các cấu trúc xử lý lỗi¶
1. Cấu trúc cơ bản¶
try:
so = int(input("Nhập một số: "))
print(f"Bạn đã nhập: {so}")
except ValueError:
print("Lỗi: Vui lòng nhập số hợp lệ!")
2. Cấu trúc với nhiều loại lỗi¶
try:
so1 = int(input("Nhập số thứ nhất: "))
so2 = int(input("Nhập số thứ hai: "))
ket_qua = so1 / so2
print(f"Kết quả: {ket_qua}")
except ValueError:
print("Lỗi: Vui lòng nhập số hợp lệ!")
except ZeroDivisionError:
print("Lỗi: Không thể chia cho 0!")
3. Cấu trúc bắt tất cả các lỗi¶
try:
# Một số thao tác có thể gây lỗi
ket_qua = eval(input("Nhập biểu thức toán học: "))
print(f"Kết quả: {ket_qua}")
except Exception as e:
print(f"Đã xảy ra lỗi: {e}")
4. Cấu trúc đầy đủ (try-except-else-finally)¶
try:
diem = float(input("Nhập điểm (0-10): "))
if diem < 0 or diem > 10:
raise ValueError("Điểm phải từ 0 đến 10")
except ValueError as e:
print(f"Lỗi: {e}")
else:
print(f"Điểm hợp lệ: {diem}")
if diem >= 8:
print("Học lực: Giỏi")
elif diem >= 6.5:
print("Học lực: Khá")
else:
print("Học lực: Trung bình")
finally:
print("Cảm ơn bạn đã sử dụng chương trình!")
III. Ví dụ minh họa thực tế¶
Ví dụ 1: Nhập điểm an toàn¶
Đề bài: Viết chương trình nhập điểm học sinh với xử lý lỗi. Chương trình phải đảm bảo:
- Chỉ chấp nhận số thực hợp lệ (xử lý lỗi khi nhập chữ hoặc ký tự đặc biệt)
- Điểm phải trong khoảng từ 0 đến 10
- Cho phép nhập lại nếu dữ liệu không hợp lệ
- Hiển thị thông báo lỗi rõ ràng cho từng trường hợp
def nhap_diem_an_toan():
while True:
try:
diem = float(input("Nhập điểm (0-10): "))
if 0 <= diem <= 10:
return diem
else:
print("Điểm phải trong khoảng 0-10!")
except ValueError:
print("Vui lòng nhập số hợp lệ!")
# Sử dụng hàm
diem_toan = nhap_diem_an_toan()
print(f"Điểm Toán của bạn: {diem_toan}")
Ví dụ 2: Máy tính an toàn¶
Đề bài: Tạo máy tính đơn giản thực hiện 4 phép toán cơ bản (+, -, *, /) với xử lý lỗi toàn diện:
- Xử lý lỗi khi nhập không phải số cho 2 toán hạng
- Xử lý lỗi chia cho 0 (ZeroDivisionError)
- Xử lý lỗi khi nhập phép toán không hợp lệ
- Hiển thị thông báo lỗi cụ thể cho từng loại lỗi
- Đảm bảo chương trình không bị crash trong mọi trường hợp
def may_tinh_an_toan():
try:
so1 = float(input("Nhập số thứ nhất: "))
phep_toan = input("Nhập phép toán (+, -, *, /): ")
so2 = float(input("Nhập số thứ hai: "))
if phep_toan == "+":
ket_qua = so1 + so2
elif phep_toan == "-":
ket_qua = so1 - so2
elif phep_toan == "*":
ket_qua = so1 * so2
elif phep_toan == "/":
if so2 == 0:
raise ZeroDivisionError("Không thể chia cho 0")
ket_qua = so1 / so2
else:
raise ValueError("Phép toán không hợp lệ")
print(f"{so1} {phep_toan} {so2} = {ket_qua}")
except ValueError as e:
print(f"Lỗi giá trị: {e}")
except ZeroDivisionError as e:
print(f"Lỗi chia: {e}")
except Exception as e:
print(f"Lỗi không xác định: {e}")
# Sử dụng máy tính
may_tinh_an_toan()
Ví dụ 3: Đọc file an toàn¶
Đề bài: Viết chương trình đọc nội dung file text với xử lý đầy đủ các lỗi có thể xảy ra:
- Xử lý lỗi file không tồn tại (FileNotFoundError)
- Xử lý lỗi không có quyền truy cập file (PermissionError)
- Xử lý các lỗi khác khi đọc file (encoding, I/O errors...)
- Hiển thị nội dung file nếu đọc thành công
- Đảm bảo file được đóng đúng cách trong mọi trường hợp
def doc_file_an_toan(ten_file):
try:
with open(ten_file, 'r', encoding='utf-8') as file:
noi_dung = file.read()
print(f"Nội dung file {ten_file}:")
print(noi_dung)
except FileNotFoundError:
print(f"Lỗi: Không tìm thấy file '{ten_file}'")
except PermissionError:
print(f"Lỗi: Không có quyền đọc file '{ten_file}'")
except Exception as e:
print(f"Lỗi khi đọc file: {e}")
# Sử dụng hàm
doc_file_an_toan("diem_so.txt")
Ví dụ 4: Quản lý danh sách học sinh¶
Đề bài: Viết chương trình quản lý danh sách học sinh với menu lựa chọn và xử lý lỗi toàn diện:
- Menu có 4 tùy chọn: Thêm học sinh, Xem danh sách, Tìm học sinh, Thoát
- Xử lý lỗi khi nhập lựa chọn menu không hợp lệ
- Xử lý lỗi khi thêm học sinh: tên trống, tuổi không hợp lệ (phải từ 6-18)
- Xử lý lỗi tìm kiếm trong danh sách trống
- Xử lý ngắt chương trình bằng Ctrl+C (KeyboardInterrupt)
- Cho phép chạy liên tục cho đến khi người dùng chọn thoát
def quan_ly_hoc_sinh():
danh_sach = []
while True:
try:
print("\n=== QUẢN LÝ HỌC SINH ===")
print("1. Thêm học sinh")
print("2. Xem danh sách")
print("3. Tìm học sinh")
print("4. Thoát")
lua_chon = int(input("Chọn chức năng (1-4): "))
if lua_chon == 1:
ten = input("Nhập tên học sinh: ").strip()
if not ten:
raise ValueError("Tên không được để trống")
tuoi = int(input("Nhập tuổi: "))
if tuoi < 6 or tuoi > 18:
raise ValueError("Tuổi phải từ 6-18")
danh_sach.append({"ten": ten, "tuoi": tuoi})
print("Đã thêm học sinh thành công!")
elif lua_chon == 2:
if not danh_sach:
print("Danh sách trống!")
else:
print("Danh sách học sinh:")
for i, hs in enumerate(danh_sach, 1):
print(f"{i}. {hs['ten']} - {hs['tuoi']} tuổi")
elif lua_chon == 3:
ten_tim = input("Nhập tên cần tìm: ").strip()
tim_thay = False
for hs in danh_sach:
if ten_tim.lower() in hs['ten'].lower():
print(f"Tìm thấy: {hs['ten']} - {hs['tuoi']} tuổi")
tim_thay = True
if not tim_thay:
print("Không tìm thấy học sinh!")
elif lua_chon == 4:
print("Tạm biệt!")
break
else:
raise ValueError("Lựa chọn không hợp lệ")
except ValueError as e:
print(f"Lỗi: {e}")
except KeyboardInterrupt:
print("\nTạm dừng chương trình!")
break
except Exception as e:
print(f"Lỗi không xác định: {e}")
# Chạy chương trình
quan_ly_hoc_sinh()
IV. Bài tập vận dụng tại lớp¶
Bài 1: Nhập tuổi an toàn¶
Đề bài: Viết chương trình nhập tuổi của học sinh. Sử dụng try-except
để xử lý các trường hợp:
- Người dùng nhập không phải số
- Tuổi âm hoặc lớn hơn 100
💡 Phân tích đề
Các bước thực hiện:
- Sử dụng try-except để bao bọc việc nhập và chuyển đổi
- Bắt ValueError khi nhập không phải số
- Kiểm tra logic: tuổi phải từ 0 đến 100
- Thông báo lỗi rõ ràng cho người dùng
- Cho phép nhập lại khi có lỗi
Input/Output mẫu:
Input | Lỗi | Xử lý |
---|---|---|
"abc" |
ValueError |
"Vui lòng nhập số!" |
-5 |
Logic error |
"Tuổi phải từ 0-100!" |
25 |
Hợp lệ |
"Tuổi của bạn: 25" |
💡 Gợi ý code
while True:
try:
tuoi = int(input("Nhập tuổi của bạn: "))
if tuoi < 0 or tuoi > 100:
print("Tuổi phải từ 0 đến 100!")
continue
print(f"Tuổi của bạn: {tuoi}")
break
except ValueError:
print("Vui lòng nhập một số hợp lệ!")
Bài 2: Tính điểm trung bình an toàn¶
Đề bài: Viết chương trình tính điểm trung bình từ 3 điểm số. Xử lý lỗi khi người dùng nhập sai định dạng hoặc điểm ngoài khoảng 0-10.
💡 Phân tích đề
Các bước thực hiện:
- Tạo hàm nhập điểm an toàn với try-except
- Bắt ValueError cho lỗi chuyển đổi
- Kiểm tra điểm trong khoảng 0-10
- Nhập 3 điểm và tính trung bình
- Hiển thị kết quả với xếp loại
Input/Output mẫu:
Điểm 1 | Điểm 2 | Điểm 3 | Trung bình | Xếp loại |
---|---|---|---|---|
8.5 |
7.0 |
9.0 |
8.17 |
Giỏi |
💡 Gợi ý code
def nhap_diem(mon):
while True:
try:
diem = float(input(f"Nhập điểm {mon}: "))
if diem < 0 or diem > 10:
print("Điểm phải từ 0 đến 10!")
continue
return diem
except ValueError:
print("Vui lòng nhập số hợp lệ!")
# Nhập 3 điểm
diem1 = nhap_diem("Toán")
diem2 = nhap_diem("Văn")
diem3 = nhap_diem("Anh")
# Tính trung bình
trung_binh = (diem1 + diem2 + diem3) / 3
print(f"Điểm trung bình: {trung_binh:.2f}")
Bài 3: Truy cập danh sách an toàn¶
Đề bài: Viết chương trình truy cập phần tử trong danh sách theo chỉ số. Xử lý lỗi IndexError
khi chỉ số vượt quá phạm vi.
💡 Phân tích đề
Các bước thực hiện:
- Tạo danh sách mẫu
- Hiển thị danh sách và độ dài
- Nhập chỉ số từ người dùng
- Bắt IndexError khi chỉ số vượt quá
- Bắt ValueError khi nhập không phải số
Input/Output mẫu:
Danh sách | Chỉ số | Kết quả |
---|---|---|
[10,20,30] |
1 |
Phần tử: 20 |
[10,20,30] |
5 |
Chỉ số vượt quá! |
💡 Gợi ý code
danh_sach = [10, 20, 30, 40, 50]
print(f"Danh sách: {danh_sach}")
print(f"Độ dài: {len(danh_sach)}")
while True:
try:
chi_so = int(input("Nhập chỉ số cần truy cập: "))
phan_tu = danh_sach[chi_so]
print(f"Phần tử tại chỉ số {chi_so}: {phan_tu}")
break
except IndexError:
print(f"Chỉ số phải từ 0 đến {len(danh_sach)-1}!")
except ValueError:
print("Vui lòng nhập số nguyên!")
Bài 4: ATM đơn giản¶
Đề bài: Viết chương trình đơn giản mô phỏng ATM: nhập số tiền cần rút, xử lý các lỗi có thể xảy ra (số tiền âm, không đủ số dư, nhập sai định dạng).
💡 Phân tích đề
Các bước thực hiện:
- Khởi tạo số dư tài khoản
- Hiển thị menu ATM
- Nhập số tiền cần rút với try-except
- Kiểm tra số tiền hợp lệ (> 0)
- Kiểm tra đủ số dư
- Thực hiện giao dịch và cập nhật số dư
Input/Output mẫu:
Số dư | Số tiền rút | Kết quả |
---|---|---|
1,000,000 |
500,000 |
Thành công, còn 500,000 |
1,000,000 |
1,500,000 |
Không đủ số dư! |
💡 Gợi ý code
so_du = 1000000 # Số dư ban đầu
print("=== ATM ===")
print(f"Số dư hiện tại: {so_du:,} VND")
while True:
try:
so_tien = int(input("Nhập số tiền cần rút: "))
if so_tien <= 0:
print("Số tiền phải lớn hơn 0!")
continue
if so_tien > so_du:
print("Không đủ số dư!")
continue
so_du -= so_tien
print(f"Rút thành công {so_tien:,} VND")
print(f"Số dư còn lại: {so_du:,} VND")
break
except ValueError:
print("Vui lòng nhập số tiền hợp lệ!")
V. Bài tập về nhà¶
Bài 1: Máy tính cá nhân¶
Đề bài: Viết chương trình "Máy tính cá nhân" có thể thực hiện 4 phép toán cơ bản. Chương trình phải xử lý tất cả các lỗi có thể xảy ra và cho phép người dùng tính toán liên tục.
💡 Phân tích đề
Các bước thực hiện:
- Tạo menu lựa chọn phép toán (+, -, *, /)
- Nhập 2 số với xử lý ValueError
- Thực hiện phép toán với xử lý ZeroDivisionError
- Hiển thị kết quả
- Hỏi người dùng có muốn tiếp tục không
- Xử lý lỗi nhập lựa chọn menu
Input/Output mẫu:
Phép toán | Số 1 | Số 2 | Kết quả |
---|---|---|---|
/ |
10 |
0 |
Lỗi: Không thể chia cho 0! |
* |
5 |
3 |
15 |
Bài 2: Quản lý điểm số học sinh¶
Đề bài: Viết chương trình quản lý điểm số học sinh. Chương trình cho phép:
- Nhập điểm cho từng môn học
- Tính điểm trung bình
- Xếp loại học lực
- Xử lý mọi lỗi nhập liệu
💡 Phân tích đề
Các bước thực hiện:
- Tạo dictionary lưu điểm các môn
- Menu: thêm điểm, xem điểm, tính trung bình
- Xử lý ValueError khi nhập điểm
- Kiểm tra điểm trong khoảng 0-10
- Tính trung bình và xếp loại
- Xử lý lỗi khi dictionary rỗng
Input/Output mẫu:
Môn | Điểm | Trung bình | Xếp loại |
---|---|---|---|
Toán |
8.5 |
8.17 |
Giỏi |
Văn |
7.5 |
||
Anh |
8.5 |
Bài 3: Đọc ghi file điểm số¶
Đề bài: Viết chương trình đọc và ghi file điểm số. Chương trình phải xử lý các lỗi:
- File không tồn tại
- Không có quyền truy cập
- Dữ liệu trong file không đúng định dạng
💡 Phân tích đề
Các bước thực hiện:
- Tạo file mẫu với định dạng: tên,điểm1,điểm2,điểm3
- Đọc file với xử lý FileNotFoundError
- Xử lý PermissionError khi không có quyền
- Parse dữ liệu với xử lý ValueError
- Ghi file mới với xử lý lỗi
- Sử dụng finally để đóng file
Input/Output mẫu:
File | Nội dung | Trạng thái |
---|---|---|
diem.txt |
An,8.5,7.0,9.0 |
Đọc thành công |
khong_ton_tai.txt |
Lỗi: File không tồn tại |
Bài 4: Game đoán số¶
Đề bài: Viết chương trình "Trò chơi đoán số" với xử lý lỗi hoàn chỉnh:
- Máy tính tạo số ngẫu nhiên từ 1-100
- Người chơi đoán số
- Xử lý lỗi nhập liệu và giới hạn số lần đoán
💡 Phân tích đề
Các bước thực hiện:
- Import random và tạo số ngẫu nhiên
- Giới hạn số lần đoán (ví dụ: 7 lần)
- Vòng lặp nhận dự đoán với try-except
- Xử lý ValueError khi nhập không phải số
- Kiểm tra phạm vi 1-100
- Đưa ra gợi ý lớn hơn/nhỏ hơn
- Thông báo thắng/thua
Input/Output mẫu:
Lần | Dự đoán | Số bí mật | Gợi ý |
---|---|---|---|
1 |
50 |
67 |
Lớn hơn! |
2 |
80 |
67 |
Nhỏ hơn! |
3 |
67 |
67 |
Chính xác! |
VI. Ghi chú quan trọng¶
- Nguyên tắc: Chỉ sử dụng
try-except
cho các lỗi có thể xảy ra, không lạm dụng. - Cụ thể hóa lỗi: Ưu tiên bắt lỗi cụ thể thay vì dùng
except
chung. - Thông báo rõ ràng: Cung cấp thông báo lỗi dễ hiểu cho người dùng.
- finally: Sử dụng để dọn dẹp tài nguyên (đóng file, kết nối database...).
- raise: Có thể tự tạo ra lỗi khi cần thiết bằng từ khóa
raise
. - Logging: Trong ứng dụng thực tế, nên ghi log lỗi để theo dõi.