Hướng dẫn ngắn gọn về ngoại lệ Python
26/12/2022 01:19
Nhầm lẫn về lỗi lập trình? Trong bài viết này, bạn sẽ tìm hiểu ngoại lệ Python là gì, cách xử lý chúng và cách tận dụng chúng khi viết và tổ chức mã của bạn .
Lỗi rất phổ biến trong lập trình. Trong Python, chúng tôi sử dụng thuật ngữ “ngoại lệ” cho các lỗi xảy ra trong quá trình thực thi mã. Có thể là lỗi đánh máy, mã hóa mất tập trung hoặc do mã đạt đến trạng thái không hợp lệ, đó là điều không thể tránh khỏi: bạn càng viết nhiều chương trình Python, bạn sẽ càng phải đối mặt và xử lý các ngoại lệ Python nhiều hơn.
Việc xử lý ngoại lệ trong Python thoạt nghe có vẻ khó khăn hoặc bí truyền, nhưng nó là nền tảng cho lộ trình học Python của bạn. Bằng cách dự đoán chính xác các sự cố tiềm ẩn và xử lý các trường hợp ngoại lệ, chúng tôi có thể khắc phục sự cố và ngăn không cho mã bị lỗi – trong khi vẫn giữ cho người dùng hài lòng và được cung cấp đầy đủ thông tin. Khả năng xử lý đúng các ngoại lệ Python sẽ giúp mã của bạn trở nên đáng tin cậy và dễ hiểu hơn về lâu dài.
Trong bài viết này, chúng ta sẽ khám phá các ngoại lệ Python là gì, cách chúng ta có thể xử lý chúng và cách tận dụng chúng bằng cách tạo các ngoại lệ của riêng mình và sử dụng chúng để giữ cho mã của chúng ta được tổ chức.
Có gì trong Ngoại lệ Python?
Trong Python, chúng tôi nói rằng các ngoại lệ được đưa ra khi một thao tác không hợp lệ được thực hiện, chẳng hạn như cố gắng cộng văn bản và số lại với nhau hoặc chia một số cho 0. Bất cứ khi nào điều này xảy ra, Python sẽ hiển thị thông báo ngoại lệ và mã sẽ ngừng thực thi tại thời điểm đó.
Ví dụ, hãy xem xét tập lệnh code.py, chứa một dòng bên dưới:
int ( 'a' ) |
Chúng tôi đã mong đợi mã này đưa ra một ngoại lệ Python - sau tất cả, chúng tôi không thể chuyển đổi chuỗi 'a'
thành số nguyên. Nếu thử thực thi tập lệnh, bạn sẽ thấy một thông báo ngoại lệ tương tự như sau:
Traceback (most recent call last): File "code.py" , line 1 , in <module> int ( 'a' ) ValueError: invalid literal for int () with base 10 : 'a' < / module> |
Thông báo ngoại lệ có thể trông đáng sợ, nhưng nó thực sự rất hữu ích. Nó cho chúng ta biết:
- Loại ngoại lệ Python nào đã được nêu ra (trong trường hợp này là a
ValueError
). - Dòng nào đã kích hoạt ngoại lệ (dòng 1 của tập lệnh code.py).
- Tại sao ngoại lệ được nêu ra. Thông tin này được truyền tải thông qua thông báo ngoại lệ Python
invalid literal for int() with base 10: 'a'
, nghĩa là'a'
không thể chuyển đổi chuỗi thành số nguyên.
Các loại ngoại lệ phổ biến trong Python
Như bạn có thể mong đợi, có rất nhiều loại ngoại lệ Python ngoài kia. Hãy xem xét một số ngoại lệ Python mà bạn sẽ gặp phải thường xuyên nhất, cùng với các mẫu mã sẽ nêu ra chúng.
Lỗi cú pháp
Ngoại lệ này xuất hiện khi bạn viết mã Python sai cú pháp. Nguyên nhân phổ biến của việc này là do quên sử dụng dấu hai chấm trên if ...
câu lệnh : hoặc để lại dấu ngoặc nhọn/dấu ngoặc đơn chưa khớp trong mã. Hãy xem những ví dụ này:
# Missing a colon at the end of the if statement value = 10 if value < 5 # SyntaxError: invalid syntax # Different types of braces/parentheses on each side values = [ 2 , 5 , 4 , 9 , 10 ) # SyntaxError: closing parenthesis ')' does not match opening parenthesis '[' |
Nếu bạn gặp phải ngoại lệ Python này, giải pháp là tìm lỗi cú pháp trong mã của bạn và sửa chúng.
LoạiLỗi
Ngoại lệ này cho biết rằng bạn đã cố thực hiện một thao tác bằng cách sử dụng loại dữ liệu sai. Như ví dụ sau minh họa, bạn không thể “thêm” một số và một chuỗi:
value = 5 name = 'John' print (value + name) # TypeError: unsupported operand type(s) for +: 'int' and 'str' |
Ngoại lệ này thường xuất hiện khi bạn cố gắng thực hiện một thao tác với giá trị Không có – là loại không chấp nhận thao tác nào. .
Giá trịError
Ngoại lệ này xuất hiện khi bạn cung cấp đúng loại dữ liệu cho một thao tác nhưng có giá trị không hợp lệ. Ví dụ: chúng ta không thể tính logarit của một số âm:
import math math.log( - 1 ) # ValueError: math domain error |
ZeroDivisionLỗi
Như tên gợi ý, ngoại lệ này xảy ra khi bạn cố gắng chia một số cho 0:
2 / 0 # ZeroDivisionError: division by zero |
Bạn có thể coi nó như một phiên bản "chuyên dụng" của một tệp ValueError
.
Chỉ mụcLỗi
Ngoại lệ này xảy ra khi bạn cung cấp chỉ mục không hợp lệ cho một chuỗi – ví dụ: nếu danh sách chỉ có 5 phần tử nhưng bạn cố lấy phần tử tại chỉ mục 100
:
values = [ 1 , 5 , 11 , 17 , 22 ] print (values[ 0 ]) print (values[ 2 ]) print (values[ 100 ]) # IndexError: list index out of range |
Lỗi chính
Đây là đối tác từ điển của IndexError
. Ngoại lệ được đưa ra khi bạn cung cấp khóa không tồn tại cho từ điển Python:
grades = { 'John' : 10 , 'Mary' : 8 , 'Steve' : 9 } print (grades[ 'John' ]) print (grades[ 'Steve' ]) print (grades[ 'Mark' ]) # KeyError: 'Mark' |
Cách xử lý ngoại lệ trong Python
Đến giờ, có lẽ bạn đã hiểu rõ về cách thức hoạt động của các ngoại lệ Python và ý nghĩa của chúng. Nhưng làm thế nào để chúng ta đối phó với họ?
Chắc chắn, một số trường hợp ngoại lệ rất đơn giản: Nếu tôi gặp SyntaxError
lỗi , giải pháp đơn giản là sửa cú pháp trong mã của riêng tôi. Nhưng nếu tôi không biết những phím nào trong từ điển thì sao? Điều gì xảy ra nếu tôi cần tính logarit của một số nhận được từ đầu vào của người dùng, số này có thể âm hoặc không?
Nhập try/except
khối. Đây là một khối mã đặc biệt cố gắng chạy một dòng (hoặc một số dòng) mã mà chúng tôi biết có thể gây ra ngoại lệ Python. Nếu ngoại lệ thực sự được đưa ra, nó sẽ đi vào khối ngoại trừ , xử lý tình huống và giữ cho mã không bị lỗi.
Đây là một ví dụ về giao diện của nó:
import math number = 5 print ( 'Calculating the logarithm of' , number) try : print (math.log(number)) except ValueError: print ( 'Unable to calculate logarithm of' , number, 'because it is a negative number. Please provide another number.' ) |
Chạy mã ở trên và thay đổi dòng number = 5
thành giá trị âm. Như chúng ta đã thấy trước đây, logarit của một số âm không tồn tại, dẫn đến a ValueError
trong mã của chúng ta. Tuy nhiên, bằng cách đặt dòng math.log(number)
dưới try:
khối, chúng tôi có thể dự đoán và xử lý vấn đề này.
Bất cứ khi nào ValueError
kích hoạt, mã chỉ cần bỏ qua thẳng vào except ValueError:
khối. Trong khối đó, chúng tôi thông báo cho người dùng rằng họ nên cung cấp một số khác cho tập lệnh. Thay vì gặp sự cố, chương trình của chúng tôi hiện xử lý tình huống một cách duyên dáng và thông báo cho người dùng. Ngăn chặn khủng hoảng!
Xử lý ngoại lệ Python như một chuyên gia
Bây giờ chúng ta đã có hiểu biết cơ bản về việc sử dụng try/except
các khối để xử lý ngoại lệ Python. Nhưng các khối mã này có thể được mở rộng theo một số cách mà chúng ta sẽ khám phá bên dưới.
Bạn có thể sử dụng nhiều except
khối để xử lý các loại ngoại lệ khác nhau. Trong mã bên dưới, chúng tôi tính logarit của x
chia cho y
trong khi xử lý các ngoại lệ tiềm năng ZeroDivisionError
và ValueError
bên trong các except
khối tương ứng của chúng. Hãy thử chạy mã sau khi thay đổi giá trị của x
hoặc y
và bạn sẽ thấy ngoại lệ tương ứng đang được xử lý:
x = 1 y = - 2 try : value = x / y print (math.log(value)) except ZeroDivisionError: print ( 'Cannot divide by zero' ) except ValueError: print ( 'Cannot calculate log of negative value' ) |
Cũng có thể nhóm hai hoặc nhiều ngoại lệ vào một except
khối duy nhất bằng cách sử dụng dấu ngoặc đơn:
x = 1 y = - 2 try : value = x / y print (math.log(value)) except (ZeroDivisionError, ValueError) as e: print ( 'Got an error:' , e) |
Vì chúng tôi không biết trước liệu mã sẽ kích hoạt a ZeroDivisionError
hay a ValueError
, nên chúng tôi sử dụng except ... as e
cấu trúc để in thông báo có trong ngoại lệ đang được xử lý. Ví dụ: nếu mã kích hoạt a ZeroDivisionError
, thông báo được in sẽ trở thành " Got an error: division by zero
".
Một tùy chọn khác là sử dụng except Exception
để xử lý (hầu như) mọi ngoại lệ Python trong một khối:
x = 1 y = - 2 try : value = x / y print (math.log(value)) except Exception as e: print ( 'Got an error:' , e) |
Nhưng hãy cẩn thận: mặc dù việc xử lý ngoại lệ “bắt tất cả” này có thể hữu ích trong một số trường hợp nhất định, nhưng nó thực sự có thể khiến mã của bạn khó hiểu và khó gỡ lỗi hơn. Một except Exception
khối cuối cùng có thể ẩn các ngoại lệ mà bạn thậm chí không xem xét trước!
Cuối cùng, có hai khối tùy chọn cho một try/except
khối:
- Khối
else
này chỉ thực thi nếu không có ngoại lệ nào được đưa ra trongtry
khối trước đó. - Khối
finally
luôn thực thi - bất kể có ngoại lệ Python nào được đưa ra hay không.
Đây là ví dụ của chúng ta trông như thế nào với các khối ở trên được thêm vào. (Một lần nữa, thay đổi giá trị của x
và y
để xem các thông báo khác nhau được in.)
x = 1 y = - 2 try : value = x / y log_value = math.log(value) except ZeroDivisionError: print ( 'Cannot divide by zero' ) except ValueError: print ( 'Cannot calculate log of negative value' ) else : print ( 'Log value is' , log_value) finally : print ( 'Code has finished' ) |
Như bạn có thể thấy, log_value
được tính bên trong try
khối. Trong quá trình này, bất kỳ trường hợp ngoại lệ nào mà chúng tôi dự đoán sẽ bị chặn bởi except
khối tương ứng. Nếu không có ngoại lệ nào được đưa ra, mã sẽ nhập else
khối và hiển thị giá trị log_value
đã được tính toán thành công. Sau đó, finally
khối kích hoạt và hiển thị thông báo kết thúc – bất kể mã trước đó có đưa ra ngoại lệ hay không.
Tạo và nâng cao các ngoại lệ của riêng bạn trong Python
Nếu bạn cần linh hoạt hơn trong việc xử lý lỗi của mình, Python cho phép bạn xác định các loại ngoại lệ tùy chỉnh. Bạn chỉ cần tạo một lớp với tên của ngoại lệ tùy chỉnh của mình:
class NumberTooLargeError(Exception): pass |
Đừng lo lắng nếu bạn chưa biết lớp là gì – bạn sẽ không thực sự cần biết về chúng để tạo và sử dụng các ngoại lệ tùy chỉnh.
Sau đó, bạn có thể tăng chúng bằng cách sử dụng raise
từ khóa và chúng sẽ hoạt động giống như bất kỳ ngoại lệ Python nào khác. Ví dụ: mã bên dưới đưa ra một ngoại lệ hiển thị thông tin bất cứ khi nào giá trị của x
vượt quá một giới hạn nhất định:
x = 10 limit = 100 if x > limit: message = f "Value {x} is above the limit {limit}" raise NumberTooLargeError(message) |
Nếu chúng tôi thay đổi giá trị x thành 200, chúng tôi sẽ nhận được thông báo lỗi này:
NumberTooLargeError: Value 1000 is above the limit 200 |
Bây giờ, bạn có thể thắc mắc Tại sao tôi lại muốn chương trình của mình bị sập? . Câu trả lời thực sự phụ thuộc vào những gì bạn đang cố gắng đạt được với mã của mình.
Nếu bạn đang viết mã mà người khác có thể sử dụng, sẽ rất hữu ích nếu bạn đưa ra các ngoại lệ cho biết rõ ràng lý do tại sao một thao tác nhất định không hợp lệ. Sau đó, bất kỳ ai đang sử dụng mã đó đều có thể quyết định xem họ có cần thay đổi điều gì đó trong mã của riêng họ hay họ muốn sử dụng một try/except
khối để phá vỡ các ngoại lệ tùy chỉnh của bạn. Trong mọi trường hợp, việc giữ cho mã của bạn rõ ràng và có tổ chức luôn được đền đáp!