1.1 Phát sinh lỗi
Lỗi (và ngoại lệ) là một phần không thể thiếu của lập trình. Chúng xảy ra khi chương trình gặp phải những tình huống không lường trước, mà nó không thể xử lý. Trong Python có hệ thống xử lý ngoại lệ, cho phép bắt và xử lý lỗi, ngăn chặn chương trình bị dừng đột ngột.
Ngoại lệ thường xảy ra trong các tình huống sau:
Lỗi cú pháp:
Những lỗi này được phát hiện trong giai đoạn biên dịch mã và liên quan đến ngữ pháp sai của ngôn ngữ Python. Ví dụ, dấu hai chấm bị thiếu hoặc từ khóa không chính xác.
if True:
print("Hello")
Lỗi thời gian chạy (Runtime Errors)
:
Những lỗi này xảy ra trong thời gian chạy chương trình và có thể do nhiều nguyên nhân khác nhau, chẳng hạn như chia cho không, truy cập vào chỉ số không tồn tại của danh sách, sử dụng sai loại dữ liệu, v.v.
print(1 / 0) # ZeroDivisionError
Lỗi logic:
Những lỗi này xảy ra khi chương trình chạy không có sự cố, nhưng cho kết quả sai do lỗi trong logic của chương trình. Lỗi logic không gây ra ngoại lệ và khó gỡ lỗi hơn.
Lỗi logic thường được gọi là bug — như là một cái thiếu sót nào đó trong chức năng của chương trình. Còn lỗi thời gian chạy được gọi là ngoại lệ. Đối với mỗi lỗi như vậy, Python tạo ra một đối tượng đặc biệt (ngoại lệ) và "ném" nó vào chương trình...
1.2 Đường đi của ngoại lệ
Khi một ngoại lệ xuất hiện trong Python, nó sẽ được nâng lên qua ngăn xếp lời gọi cho đến khi được xử lý. Ngăn xếp lời gọi là chuỗi các lời gọi hàm dẫn đến ngoại lệ.
Cơ chế nâng ngoại lệ
- Phát sinh ngoại lệ: Khi xảy ra lỗi, Python tạo đối tượng ngoại lệ.
- Tìm kiếm bộ xử lý ngoại lệ: Trình thông dịch Python bắt đầu tìm kiếm bộ xử lý ngoại lệ trong khối mã hiện tại. Nếu không tìm thấy, nó chuyển sang khối mã tiếp theo đã gọi hàm hiện tại.
- Nâng ngoại lệ qua ngăn xếp: Quá trình này lặp lại cho đến khi tìm thấy bộ xử lý hoặc ngăn xếp lời gọi bị cạn kiệt.
- Kết thúc chương trình: Nếu không tìm thấy bộ xử lý, chương trình kết thúc và hiển thị thông báo lỗi.
Ví dụ:
def func_a():
func_b()
def func_b():
func_c()
def func_c():
print(1 / 0) # Tại đây phát sinh ngoại lệ ZeroDivisionError
func_a()
Trong ví dụ này, ngoại lệ ZeroDivisionError
xảy ra trong hàm
func_c
, sau đó được nâng lên qua ngăn xếp lời gọi qua func_b
và func_a
.
Nếu không có bộ xử lý nào được tìm thấy, chương trình sẽ kết thúc với
lỗi.
1.3 Đọc log
Khi chương trình kết thúc do ngoại lệ không được xử lý, Python hiển thị theo dõi ngăn xếp (traceback), điều này giúp nhà phát triển hiểu được điều gì đã xảy ra. Theo dõi ngăn xếp chứa thông tin về chuỗi lời gọi hàm dẫn đến ngoại lệ và có thể được phân tích để gỡ lỗi chương trình.
Ví dụ về theo dõi ngăn xếp
Traceback (most recent call last):
File "example.py", line 10, in
func_a()
File "example.py", line 2, in func_a
func_b()
File "example.py", line 5, in func_b
func_c()
File "example.py", line 8, in func_c
print(1 / 0)
ZeroDivisionError: division by zero
Phân tích theo dõi ngăn xếp
- Loại ngoại lệ và thông điệp: Cuối cùng của theo dõi chỉ ra loại ngoại lệ và thông điệp. Trong
ví dụ này là
ZeroDivisionError: division by zero
. - Chuỗi lời gọi: Theo dõi ngăn xếp cho thấy chuỗi lời gọi
hàm. Trong ví dụ của chúng ta, lỗi xảy ra tại dòng
print(1 / 0)
trong hàmfunc_c
, hàm này được gọi từfunc_b
, hàm này lại được gọi từfunc_a
. - Tệp tin và dòng mã: Trong mỗi dòng theo dõi chỉ ra tệp tin và số dòng, nơi xảy ra lời gọi. Điều này giúp nhanh chóng tìm và sửa lỗi trong mã.
Ứng dụng thực tế của theo dõi ngăn xếp
Theo dõi ngăn xếp là công cụ quan trọng để gỡ lỗi và phân tích chương trình. Nó giúp nhà phát triển hiểu nguyên nhân gây lỗi và tìm nơi trong mã, nơi đã xảy ra lỗi. Dưới đây là vài lời khuyên về việc sử dụng theo dõi ngăn xếp:
- Đọc từ dưới lên: Bắt đầu phân tích từ lời gọi thấp nhất trong theo dõi, vì đó là nơi xảy ra ngoại lệ.
- Kiểm tra tất cả lời gọi: Nghiên cứu tất cả các lời gọi trong theo dõi để hiểu đường đi, mà ngoại lệ đã được truyền tải.
- Sửa mã: Sử dụng thông tin từ theo dõi để sửa mã và ngăn chặn các lỗi tương tự trong tương lai.
Chi tiết hơn về ngoại lệ, bạn sẽ biết trong các bài giảng sau.
GO TO FULL VERSION