Trong phát triển phần mềm, các kiểu lỗi khác nhau có thể xảy ra. Chúng có thể là lỗi cú pháp, sai logic hay lỗi runtime.
Lỗi cú pháp hầu hết có thể xảy ra trong giai đoạn phát triển ban đầu và là kết quả của sai cú pháp. Lỗi cú pháp có thể được bắt gặp một cách dễ dàng khi chương trình được biên dịch để thực thi.
Lỗi logic, mặt khác, là kết quả của việc thực hiện logic không hợp lý. Ví dụ một chương trình truy cập vào một danh sách không thứ tự và cho là nó đã được sắp xếp. Lỗi logic là những lỗi khó theo dõi nhất.
Lỗi runtime là các lỗi thú vị nhất xảy ra, nếu chúng ta không cân nhắc tất cả các trường hợp xảy ra. Ví dụ, cố gắng để truy cập vào một tập tin không tồn tại.
Trong hướng dẫn này, chúng ta sẽ tìm hiểu cách xử lý các lỗi trong Python và cách để log lại các lỗi để hiểu sâu hơn về những gì đã sai trong ứng dụng.
Xử lý ngoại lệ trong Python
Hãy bắt đầu với một chương trình đơn giản để cộng hai số trong Python. Chương trình của chúng ta nhận hai tham số đầu vào và in tổng. Dưới đây là một chương trình Python để cộng hai con số:
1 2 3 4 | def addNumbers(a, b): print a + b addNumbers(5, 10) |
Thử chạy chương trình Python trên, và bạn sẽ được in ra tổng.
1
Trong khi viết chương trình nêu trên, chúng tôi đã không thực sự xem xét một thực tế rằng bất cứ điều gì cũng có thể sai. Điều gì xảy ra nếu một trong các tham số truyền vào không phải là một con số?
1 | addNumbers('', 10) |
Chúng tôi đã không xử lý trường hợp đó, do đó chương trình sẽ crash với thông báo lỗi sau:
1 2 3 4 5 6 | Traceback (most recent call last): File "addNumber.py", line 4, in <module> addNumbers('', 10) File "addNumber.py", line 2, in addNumbers print a + b TypeError: cannot concatenate 'str' and 'int' objects |
Chúng ta có thể xử lý vấn đề trên bằng cách kiểm tra tham số được truyền vào có là số nguyên hay không. Nhưng điều đó sẽ không giải quyết được vấn đề. Điều gì xảy ra nếu code bị lỗi vì một số lý do khác và làm cho chương trình bị crash? Làm việc với một chương trình mà bị crash khi gặp một lỗi không phải là một ứng dụng tốt. Thậm chí nếu gặp phải một lỗi không rõ, thì code nên mạnh mẽ, đủ để xử lý sự cố một cách nhẹ nhàng và cho phép người dùng biết rằng cái gì đã sai.
Xử lý ngoại lệ bằng cách sử dụng Try và Except
Trong Python, chúng ta sử dụng câu lệnh try
và except
để xử lý ngoại lệ. Bất cứ khi nào code gặp vấn đề, một ngoại lệ xảy ra mà không làm cho chương trình bị crash. Hãy sửa đổi chương trình cộng hai số để bao gồm các câu lệnh try
và except
.
1 2 3 4 5 6 7 | def addNumbers(a, b): try: return a + b except Exception as e: return 'Error occurred : ' + str(e) print addNumbers('', 10) |
Python sẽ xử lý tất cả các code bên trong câu lệnh try
và except
. Khi nó gặp một lỗi, nó chuyển qua khối except
, bỏ qua các code ở giữa.
Như đã thấy trong code ở trên, chúng tôi đã chuyển code của chúng tôi vào bên trong một câu lệnh try
và except
. Thử chạy chương trình và nó sẽ xuất ra một thông báo lỗi thay vì chương trình bị crash. Lý do là ngoại lệ cũng trả về như một thông báo ngoại lệ.
Phương pháp ở trên xử lý các trường hợp ngoại lệ bất ngờ. Hãy xem cách để xử lý ngoại lệ theo dự kiến. Giả sử rằng chúng ta đang cố gắng đọc một tập tin cụ thể bằng cách sử dụng chương trình Python, nhưng các tập tin không tồn tại. Trong trường hợp này, chúng ta sẽ xử lý ngoại lệ và cho phép người dùng biết rằng tập tin không tồn tại khi nó xảy ra. Hãy nhìn vào code đọc tập tin:
1 2 3 4 5 6 7 8 | try: try: with open('fname') as f: content = f.readlines() except IOError as e: print str(e) except Exception as e: print str(e) |
Trong đoạn code ở trên, chúng ta đã xử lý việc đọc tập tin bên trong một bộ xử lý ngoại lệ IOError
. Nếu code gặp vấn đề do không tồn tại tập tin fname
, thì lỗi sẽ được xử lý bên trong bộ xử lý IOError
. Tương tự như các ngoại lệ IOError
, có rất nhiều các ngoại lệ tiêu chuẩn giống như Arithmetic
, OverflowError
, và ImportError
, và một số khác.
Đa ngoại lệ
Chúng ta có thể xử lý nhiều ngoại lệ tại một thời điểm bằng cách gom các ngoại lệ tiêu chuẩn như sau:
1 2 3 4 5 6 | try: with open('fname') as f: content = f.readlines() printb except (IOError,NameError) as e: print str(e) |
Code ở trên sẽ xảy ra cả ngoại lệ IOError
và NameError
khi chương trình được thực thi.
Mệnh đề finally
Giả sử rằng chúng ta đang sử dụng các tài nguyên nhất định trong chương trình Python. Trong quá trình thực thi chương trình, nó đã gặp một lỗi và chỉ được thực thi nửa chừng. Trong trường hợp này, nguồn tài nguyên sẽ bị nắm giữ một cách không cần thiết. Chúng ta có thể dọn sạch các tài nguyên như vậy bằng cách sử dụng mệnh đề finally
. Hãy xem code dưới đây:
1 2 3 4 5 6 7 8 | try: filePointer = open('fname','r') try: content = filePointer.readline() finally: filePointer.close() except IOError as e: print str(e) |
Nếu trong quá trình thực thi code ở trên, một ngoại lệ xảy ra trong khi đọc tập tin, thì filePointer
sẽ bị đóng lại trong khối finally
.
Log trong Python
Khi một cái gì đó không đúng bên trong một ứng dụng, nó trở nên dễ dàng hơn để gỡ lỗi nếu chúng ta biết nguồn gốc của các lỗi. Khi một ngoại lệ xảy ra, chúng ta có thể log thông tin cần thiết để theo dõi vấn đề. Python cung cấp một thư viện log đơn giản và mạnh mẽ. Chúng ta hãy tìm cách sử dụng log trong Python.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | import logging # initialize the log settings logging.basicConfig(filename='app.log',level=logging.INFO) try: logging.info('Trying to open the file') filePointer = open('appFile','r') try: logging.info('Trying to read the file content') content = filePointer.readline() finally: filePointer.close() except IOError as e: logging.error('Error occurred ' + str(e)) |
Như đã thấy trong code ở trên, trước tiên chúng ta phải import thư viện log của Python và sau đó khởi tạo logger với tên tập tin log và cấp độ log. Có năm cấp độ log: DEBUG, INFO, WARNING, ERROR, và CRITICAL. Ở đây chúng ta đã thiết lập cấp độ log là INFO, do đó INFO và các log ở trên sẽ được log lại.
Lấy Stack Trace
Đoạn code ở trên chúng ta có một tập tin chương trình duy nhất, từ đó dễ dàng hơn để tìm ra nơi có xảy ra lỗi. Nhưng chúng ta phải làm gì khi nhiều tập tin chương trình liên quan? Trong trường hợp này, lấy Stack Trace của lỗi giúp tìm kiếm nguồn gốc của lỗi. Stack Trace của ngoại lệ có thể được log như sau:
01 02 03 04 05 06 07 08 09 10 11 | import logging #initialize the log settings logging.basicConfig(filename = ‘app.log’, level = logging.INFO) try: filePointer = open(‘appFile’,’r’) try: content = filePointer.readline() finally: filePointer.close() except IOError as e: logging.exception(str(e)) |
Nếu bạn cố gắng chạy chương trình trên, khi xảy ra một ngoại lệ, lỗi sau sẽ được log lại trong tập tin log:
1 2 3 4 5 | ERROR:root:[Errno 2] No such file or directory:'appFile' Traceback (most recent call last): File "readFile.py", line 7, in <module> filePointer = open('appFile','r') IOError: [Errno 2] No such file or directory: 'appFile' |
Tóm tắt
Trong hướng dẫn này, chúng ta đã thấy cách làm thế nào để bắt đầu xử lý các lỗi trong Python và sử dụng mô-đun log để log các lỗi. Chúng ta đã thấy cách sử dụng của try
, except
và mệnh đề finally
, chúng khá hữu ích khi xử lý lỗi trong Python.