2.25. Xử lý lỗi¶
Hầu hết các vấn đề thời gian chạy trong Python đều xuất hiện dưới dạng ngoại lệ -- một cách có tên, có cấu trúc để báo cáo rằng có điều gì đó đã xảy ra sai. ValueError, TypeError, KeyError, OSError, MemoryError đều là các ví dụ; mỗi cái là một lớp, và ném một ngoại lệ sẽ dừng lời gọi hiện tại và tìm kiếm một trình xử lý trong mã xung quanh.
2.25.1. try / except¶
Bọc một khối mã trong try để bắt bất kỳ ngoại lệ nào nó ném ra:
try:
n = int(input_text)
except ValueError:
n = 0
Nếu việc chuyển đổi int(...) thất bại, quyền điều khiển nhảy đến khối except thay vì truyền lỗi tiếp. Nếu input_text là một chuỗi số nguyên hợp lệ, khối except sẽ bị bỏ qua.
Một try đơn có thể có nhiều khối except, mỗi khối bắt một loại lỗi khác nhau:
try:
value = data[key]
except KeyError:
value = None
except TypeError:
value = -1
Python so khớp theo thứ tự; cái đầu tiên có lớp ngoại lệ phù hợp sẽ xử lý vấn đề. Bắt Exception (lớp cơ sở cho hầu hết mọi thứ) sẽ xử lý mọi lỗi; hãy giữ điều đó cho lớp ngoài cùng của chương trình nơi phương án thay thế là sập.
Cảnh báo
Một except: trần (không có lớp sau từ khóa) cũng bắt KeyboardInterrupt -- ngoại lệ mà IDE gửi khi bạn nhấn nút stop để ngắt một tập lệnh đang chạy. Một vòng lặp được bọc trong except: pass trần sẽ nuốt ngắt và tiếp tục chạy, không còn cách nào để dừng tập lệnh ngoài việc tắt nguồn.
Ưu tiên except Exception: hơn except: trần khi bạn thực sự cần bắt rộng rãi. KeyboardInterrupt kế thừa từ BaseException, không phải Exception, vì vậy except Exception: giữ cho nút dừng hoạt động.
2.25.1.1. Kiểm tra ngoại lệ¶
Để đọc thông báo đính kèm với một ngoại lệ, hãy đặt tên cho nó bằng as:
try:
f = open("data.txt")
except OSError as e:
print("could not open file:", e)
Biến được gán bởi as chỉ hợp lệ bên trong khối except.
2.25.2. else và finally¶
Một khối try có hai phần tùy chọn thêm.
else chỉ chạy khi try hoàn thành mà không ném ra ngoại lệ:
try:
value = compute()
except ValueError:
print("bad input")
else:
print("got", value)
Đặt "việc cần làm khi thành công" vào else giữ khối try hẹp -- chỉ dòng có thể thất bại mới thuộc về try.
finally chạy ở cuối bất kể điều gì -- dù try thành công, ném ra và được xử lý, hay ném ra và sắp truyền tiếp:
try:
do_work()
finally:
cleanup()
finally luôn chạy. else chỉ chạy trên đường đi không có ngoại lệ.¶
Đối với hầu hết các mẫu acquire/release, ưu tiên dùng context manager hơn là cặp try / finally -- bản thân tài nguyên tự quản lý việc dọn dẹp của mình.
2.25.3. Các ngoại lệ tích hợp phổ biến¶
Một danh sách ngắn các ngoại lệ bạn sẽ gặp thường xuyên:
ValueError-- đúng kiểu, sai giá trị (bytes([300])-- 300 đúng kiểu, nhưng nằm ngoài phạm vi byte hợp lệ là 0..255).TypeError-- sai kiểu hoàn toàn (len(42)).IndexError-- chỉ số vượt quá cuối của một dãy.AttributeError-- truy cập một thuộc tính không tồn tại ("abc".foo).OSError-- lỗi filesystem hoặc I/O.MemoryError-- hết heap. Trên một runtime bị hạn chế bộ nhớ, điều này có thể xảy ra trong quá trình hoạt động bình thường -- không chỉ trong các trường hợp bất thường.