Python: Ngoại lệ (Exception)

Python cung cấp hai tính năng rất quan trọng để xử lý bất kỳ lỗi không mong muốn nào trong các chương trình Python và thêm khả năng gỡ lỗi trong chúng:

  • Xử lý ngoại lệ: Điều này sẽ được đề cập trong bài viết này, bao gồm một danh sách các

    Ngoại lệ (Exeption)

     tiêu chuẩn có sẵn trong Python.

  • Assertion: Điều này được đề cập trong bài viết tiếp sau Assertion trong Python.

Danh sách các trường hợp ngoại lệ tiêu chuẩn:

STTTên ngoại lệ & Mô tả1

Exception

Lớp cơ sở cho tất cả các trường hợp ngoại lệ

2

StopIteration

Được kích hoạt khi phương thức next() của một trình lặp không trỏ đến bất kỳ đối tượng nào.

3

SystemExit

Được kích hoạt bởi hàm sys.exit().

4

StandardError

Lớp cơ sở cho tất cả các ngoại lệ được tích hợp sẵn ngoại trừ StopIteration và SystemExit.

5

ArithmeticError

Lớp cơ sở cho tất cả các lỗi xảy ra cho phép tính số.

6

OverflowError

Được nâng lên khi một phép tính vượt quá giới hạn tối đa cho một kiểu số.

7

FloatingPointError

Được kích hoạt khi một phép tính dấu phẩy động không thành công.

8

ZeroDivisionError

Được kích hoạt khi phép chia hoặc môđun (chia dư) cho 0 diễn ra đối với tất cả các kiểu số.

9

AssertionError

Được kích hoạt trong trường hợp câu lệnh assert không thực hiện thành công.

10

AttributeError

Được kích hoạt trong trường hợp tham chiếu hoặc gán thuộc tính không thành công.

11

EOFError

Được kích hoạt khi không có đầu vào từ hàm raw_input() hoặc input() và đến cuối tệp.

12

ImportError

Được kích hoạt khi một câu lệnh import không thành công.

13

KeyboardInterrupt

Được kích hoạt khi người dùng làm gián đoạn việc thực thi chương trình, thường bằng cách nhấn Ctrl + C.

14

LookupError

Lớp cơ sở cho tất cả các lỗi tra cứu.

15

IndexError

Được kích hoạt khi không tìm thấy chỉ mục trong một chuỗi.

16

KeyError

Được nâng lên khi không tìm thấy khóa được chỉ định trong từ điển.

17

NameError

Được kích hoạt khi không tìm thấy mã định danh trong không gian tên local hoặc global.

18

UnboundLocalError

Được kích hoạt khi cố gắng truy cập một biến local trong một hàm hoặc phương thức nhưng không có giá trị nào được gán cho nó.

19

EnvironmentError

Lớp cơ sở cho tất cả các ngoại lệ xảy ra bên ngoài môi trường Python.

20

IOError

Được kích hoạt khi thao tác nhập / xuất không thành công, chẳng hạn như câu lệnh in hoặc hàm open () khi cố gắng mở một tệp không tồn tại.

21

OSError

Được kích hoạt khi xay ra các lỗi liên quan đến hệ điều hành.

22

SyntaxError

Được kích hoạt khi có lỗi trong cú pháp Python.

23

IndentationError

Được kích hoạt khi thụt lề không được chỉ định đúng cách.

24

SystemError

Được kích hoạt khi trình thông dịch tìm thấy sự cố nội bộ, nhưng khi gặp lỗi này, trình thông dịch Python không thoát.

25

SystemExit

Được kích hoạt khi trình thông dịch Python bị thoát bằng cách sử dụng hàm sys.exit(). Nếu không được xử lý trong mã lệnh, trình thông dịch sẽ thoát.

26

TypeError

Được kích hoạt khi một hoạt động hoặc chức năng được thực hiện không hợp lệ đối với kiểu dữ liệu được chỉ định.

27

ValueError

Được kích hoạt khi hàm dựng sẵn cho một kiểu dữ liệu có kiểu đối số hợp lệ, nhưng các đối số có giá trị không hợp lệ được chỉ định.

28

RuntimeError

Được kích hoạt khi lỗi được tạo ra không thuộc bất kỳ loại nào.

29

NotImplementedError

Được kích hoạt khi một phương thức trừu tượng cần được triển khai trong một lớp kế thừa không thực sự được triển khai.

Ngoại lệ (Exception) là gì?

Ngoại lệ là một sự kiện, xảy ra trong quá trình thực thi chương trình làm gián đoạn luồng hướng dẫn bình thường của chương trình. Nói chung, khi một tập lệnh Python gặp một tình huống mà nó không thể đối phó, nó sẽ tạo ra một ngoại lệ. Một ngoại lệ là một đối tượng Python đại diện cho một lỗi.

Khi một tập lệnh Python tạo ra một ngoại lệ, nó phải xử lý ngoại lệ đó ngay lập tức nếu không nó sẽ kết thúc và thoát.

Xử lý một ngoại lệ

Nếu bạn có một số lệnh đáng ngờ có thể tạo ra một ngoại lệ, bạn có thể bảo vệ chương trình của mình bằng cách đặt mã đáng ngờ vào khối try:. Sau khối try:, hãy bao gồm một câu lệnh except:, theo sau là một khối mã xử lý vấn đề một cách tinh tế nhất có thể.

Cú pháp

Đây là cú pháp đơn giản của khối try …. except … else:

try:
   Đặt đoạn mã lệnh đáng ngờ tại đây;
   ………………….
except ExceptionI:
   Nếu phát sinh ngoại lệ ExceptionI thì khối lệnh tại đây được thực thi.
except ExceptionII:
   Nếu phát sinh ngoại lệ ExceptionII, thì khối lệnh tại đây được thực thi.
   ………………….
else:
   Nếu không có ngoại lệ nào phát sinh thì thực thi khối lệnh tại đây.

Dưới đây là một số điểm quan trọng về cú pháp trên:

  • Một câu lệnh try duy nhất có thể có nhiều câu lệnh except. Điều này hữu ích khi khối try chứa các câu lệnh có thể ném các loại ngoại lệ khác nhau.
  • Bạn cũng có thể cung cấp một mệnh đề except chung để xử lý bất kỳ ngoại lệ nào.
  • Sau (các) mệnh đề except, bạn có thể thêm một mệnh đề khác. Khối lệnh tại else sẽ được thực thi nếu mã trong khối try không phát sinh ngoại lệ.
  • Khối lệnh tại else là khối lệnh không cần sự bảo vệ của khối try:.

Ví dụ 1

Ví dụ sau mở một tệp, ghi nội dung vào tệp và in ra kết quả vì không gặp vấn đề gì:

try

:

fh

=

open

(

"testfile"

,

"w"

)

fh

.

write

(

"This is my test file for exception handling!!"

)

except

IOError

:

print

(

"Error: can\'t find file or read data")

else

:

print

(

"Written content in the file successfully")

fh

.

close

()

Kết quả:

Written content in the file successfully

Ví dụ 2

Ví dụ sau cố gắng mở một tệp mà bạn không có quyền ghi, vì vậy nó tạo ra một ngoại lệ:

try

:

fh

=

open

(

"testfile"

,

"r"

)

fh

.

write

(

"This is my test file for exception handling!!"

)

except

IOError

:

print

(

"Error: can\'t find file or read data")

else

:

print

(

"Written content in the file successfully")

Kết quả:

Error: can't find file or read data

Mệnh đề except không có ngoại lệ

Bạn cũng có thể sử dụng câu lệnh except không có phần bắt ngoại lệ theo cú pháp sau:

try:
   Đặt khối lệnh nghi ngờ phát sinh ngoại lệ tại đây;
   ………………….
except:
   Nếu có bất kỳ ngoại lệ nào thì khối lệnh tại đây sẽ được kích hoạt;
   ………………….
else:
   Nếu không có bất kỳ ngoại lệ nào thì khối lệnh tại đây sẽ được kích hoạt;

Loại câu lệnh try-except ở trên có thể bắt tất cả các ngoại lệ xảy ra. Mặc dù vậy, việc sử dụng này không được coi là một phương pháp lập trình tốt vì nó bắt được tất cả các trường hợp ngoại lệ nhưng không làm cho lập trình viên xác định được nguyên nhân gốc rễ của vấn đề có thể xảy ra.

Mệnh đề except với nhiều ngoại lệ

Bạn cũng có thể sử dụng cùng một câu lệnh except để xử lý nhiều ngoại lệ như cú pháp sau:

try:
   Đặt khối lệnh nghi ngờ phát sinh ngoại lệ tại đây;
   ………………….
except(Exception1, Exception2, …, ExceptionN):
   Nếu có bất kỳ ngoại lệ nào trong danh sách ngoại lệ ở trên
   thì khối lệnh tại đây sẽ được kích hoạt;
   ………………….
else:
   Nếu không có bất kỳ ngoại lệ nào thì khối lệnh tại đây sẽ được kích hoạt;

Mệnh đề try-finally

Khối finally là nơi để đặt khối lệnh cần phải thực thi, cho dù khối try có đưa ra ngoại lệ hay không. Cú pháp của câu lệnh try-finally là:

try:
   Khối lệnh thực thi đặt tại đây;
finally:
   Khối lệnh đặt tại đây luôn được thực thi;

Lưu ý là bạn không được sử dụng mệnh đề else cùng với mệnh đề finally.

Ví dụ

try

:

fh

=

open

(

"testfile"

,

"w"

)

fh

.

write

(

"Thử nghiệm try-finally!!"

)

finally

:

print

(

"Lỗi: Không tìm thấy file hay đọc file")

Nếu bạn không có quyền mở tệp ở chế độ ghi, thì điều này sẽ tạo ra kết quả sau:

Lỗi: Không tìm thấy file hay đọc file

Ví dụ tương tự có thể được viết rõ ràng hơn như sau:

try

: print(

"Tiến hành mở file để ghi..."

) fh =

open

(

"testfile"

,

"w"

)

try

: fh.write(

"Thu nghiem try-finally!!"

) print(

"Đã ghi xong."

)

finally

: print(

"Tiến hành đóng file..."

) fh.close() print(

"Đã đóng file."

) except IOError: print(

"Có lỗi: Không thể mở file hoặc ghi file!"

)

Kết quả:

Tiến hành mở file để ghi...
Đã ghi xong.
Tiến hành đóng file...
Đã đóng file.

Khi một ngoại lệ phát sinh trong khối try, thì việc thực thi ngay lập tức được chuyển đến khối finally. Sau khi tất cả các câu lệnh trong khối finally được thực thi, ngoại lệ sẽ được đưa ra một lần nữa và được xử lý trong các câu lệnh của phần except nếu có trong lớp cao hơn tiếp theo của câu lệnh try-except.

Đối của ngoại lệ

Một ngoại lệ có thể có đối số, là giá trị cung cấp thông tin bổ sung về vấn đề (lỗi) xảy ra. Nội dung của đối số khác nhau tùy theo ngoại lệ. Ta có thể bắt lại đối số của một ngoại lệ bằng cách cung cấp một biến trong mệnh đề except như sau:

try

:

khối lệnh;

except

kiểu_ngoại_lệ

as

đối_số

:

Ta có thể in giá trị của đối_số tại đây

Nếu bạn viết code để xử lý một ngoại lệ duy nhất, bạn có thể có một biến theo sau tên của ngoại lệ trong câu lệnh except. Nếu bạn đang bẫy nhiều ngoại lệ, bạn có thể có một biến theo sau bộ ngoại lệ.

Biến này nhận giá trị của ngoại lệ chủ yếu chứa nguyên nhân của ngoại lệ. Biến có thể nhận một giá trị duy nhất hoặc nhiều giá trị dưới dạng một bộ giá trị. Tuple này thường chứa chuỗi lỗi, số lỗi và vị trí lỗi.

Ví dụ

Sau đây là một ví dụ cho một ngoại lệ duy nhất:

# Định nghĩa một hàm

def

temp_convert

(

var

):

try

:

return

int

(

var

)

except

ValueError

as

Argument

:

print

(

"Đối số không phải chuỗi chứa số\n"

,

Argument)

# Gọi hàm

temp_convert

(

"xyz"

)

Kết quả:

Đối số không phải chuỗi chứa số
 invalid literal for int() with base 10: 'xyz'

Kích hoạt ngoại lệ

Bạn có thể nêu ra các ngoại lệ theo một số cách bằng cách sử dụng câu lệnh raise. Cú pháp chung cho câu lệnh raise như sau.

Cú pháp

raise Exception(args[, traceback]])

Ở đây, Exception là loại ngoại lệ (ví dụ: NameError) và đối số args là giá trị cho đối số ngoại lệ. Đối số là tùy chọn; nếu không được cung cấp, đối số ngoại lệ là None.

Đối số traceback cũng là tùy chọn (và hiếm khi được sử dụng trong thực tế) và nếu có, là đối tượng theo dõi được sử dụng cho ngoại lệ.

Ví dụ

Một ngoại lệ có thể là một chuỗi, một lớp hoặc một đối tượng. Hầu hết các ngoại lệ mà lõi Python nêu ra là các lớp, với một đối số là một thể hiện của lớp. Việc xác định các ngoại lệ mới khá dễ dàng và có thể được thực hiện như sau:

def functionName(level):
  

if

level <

1

: raise Exception(

"Level không hợp lệ!"

,level) # Các câu lệnh phía dưới sẽ không được thực thi # nếu ngoại lệ được kích hoạt print(

"Đã có lỗi!!!"

) functionName(

0

)

Kết quả:

Traceback (most recent call last):
  File "E:\Courses\Python\demo dictionary.py", line 7, in <module>
    functionName(0)
  File "E:\Courses\Python\demo dictionary.py", line 3, in functionName
    raise Exception("Level không hợp lệ!",level)
Exception: ('Level không hợp lệ!', 0)

Lưu ý: Để bắt một ngoại lệ, mệnh đề except phải tham chiếu đến cùng một ngoại lệ được đưa ra đối tượng lớp hoặc chuỗi đơn giản. Ví dụ, để bắt ngoại lệ ở trên, chúng ta phải viết mệnh đề except như sau:

def functionName(level):
  

if

level <

1

: raise Exception(

"Level không hợp lệ!"

,level) # Các câu lệnh phía dưới sẽ không được thực thi # nếu raise ngoại lệ print(

"Đã có lỗi!!!"

)

try

: functionName(

0

) except: print(

"Lỗi"

)

else

: print(

"Không lỗi"

)

Ngoại lệ do người dùng định nghĩa

Python cũng cho phép bạn tạo các ngoại lệ của riêng mình bằng cách dẫn xuất các lớp từ các ngoại lệ được tích hợp sẵn tiêu chuẩn.

Dưới đây là một ví dụ liên quan đến RuntimeError. Ở đây, một lớp được tạo ra có tên Networkerror và được dẫn xuất từ RuntimeError. Điều này rất hữu ích khi bạn cần hiển thị thông tin cụ thể hơn khi bắt được một ngoại lệ.

Trong khối try, ngoại lệ do người dùng định nghĩa được kích hoạt và bị bắt bởi khối except. Biến e được sử dụng để tạo một thể hiện của lớp Networkerror.

class

Networkerror

(RuntimeError): def __init__(self, arg): self.args = arg

Ở trên bạn định nghĩa 1 lớp có tên Networkerror dẫn xuất từ lớp RuntimeError. Lúc này thì ta có thể kích hoạt nó như sau:

try

: raise Networkerror(

"Bad hostname"

) except Networkerror as e: print(e.args)

Kết quả:

(‘B’, ‘a’, ‘d’, ‘ ‘, ‘h’, ‘o’, ‘s’, ‘t’, ‘n’, ‘a’, ‘m’, ‘e’)