Python Errors and Exceptions handling

Post by dangsonbk on 15-09-2017

Có nhiều tài liệu dịch Exception là 'ngoại lệ' và Exceptions Handling là 'xử lý ngoại lệ', mình thấy cách gọi này chỉ đúng về mặt dịch thuật và chưa thực sự sát nghĩa cho lắm. Trong bài viết này mình sẽ giữ nguyên từ 'Exception'.

Exception có thể hiểu là các sự kiện, biến cố khiến cho chương trình bị phá vỡ luồng thực thi. Để cho dễ hiểu, mình lấy một ví dụ sau:

print(myname)

Khi chạy sẽ trả về lỗi:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
NameError: name 'myname' is not defined

Đây là lỗi do bạn in giá trị của biến mà chưa khai báo. Ở đây Python trả về cho chúng ta thông tin về vị trí lỗi cũng như là kiểu lỗi: NameError

Lỗi trên xảy ra khá nhiều khi lập trình với Python, nguyên nhân là do sự tiện lợi trong cách tạo biến của Python khiến cho lập trình viên đôi khi thiếu đi sự chặt chẽ trong việc quản lý biến. Mình lấy một ví dụ như sau:

i = int(input("Enter a number "))
if i in range(1, 100):
    answer = "yes"
print(answer)

Sẽ chẳng có vấn đề gì nếu điều kiện i in range(1, 100) thỏa mãn. Tuy nhiên nếu điều kiện đó trả về False thì biến answer sẽ không được khởi tạo và print(answer) sẽ trả về lỗi.


Xử lý Exceptions

Python cung cấp tính năng xử lý Exception rất quan trọng và hữu dụng để xử lý bất kỳ lỗi không mong muốn nào. Danh sách các Exception được định nghĩa sẵn của Python được cung cấp ở phần cuối bài viết để bạn có thể tham khảo.

Try catch in programming

Chúng ta sẽ sử dụng các câu lệnh tryexcept để xử lý ngoại lệ. Khi code xảy ra lỗi, một exception sẽ được trả về mà không làm hỏng (crash) chương trình. Đôi khi bạn có thể gặp cụm từ như bẫy lỗi để chỉ phương pháp xử lý Exceptions.

while True:
    try:
        # Đặt bẫy lỗi
        number = int(input("Enter a number "))
        print(number)
    except Exception as e:
        # Xử lý khi lỗi sập bẫy
        print('Error occurred: ' + str(e))

Python sẽ xử lý tất cả các câu lệnh trong block try một cách bình thường, khi lỗi xảy ra các câu lệnh trong khối except sẽ được thực hiện.

Trong ví dụ trên, khi người dùng nhập vào 1 ký tự thì thay vì dừng (crash) và trả về lỗi, chương trình sẽ trả về một thông báo lỗi nhưng vẫn tiếp tục chạy vòng while tiếp theo.

Enter a number a
invalid literal for int() with base 10: 'a'

Ví dụ trên sẽ bẫy tất cả các lỗi sinh ra và không xác định rõ là lỗi gì, ở ví dụ sau, chúng ta sẽ bắt một lỗi xác định trước.

try:
    try:
        with open('filename') as f:
            f_content = f.readlines()
    except IOError as e:
        print str(e)
except Exception as e:
    print str(e)

Đoạn chương trình trên sẽ mở một file có tên là filename và đọc nội dung của nó từng dòng một sau đó đưa vào biến f_content. Trong trường hợp file filename không mở được, một lỗi IOError sẽ bị bẫy và in ra.

Ngoài lỗi IOError như trên, Python định nghĩa sẵn rất nhiều kiểu Exception khác như: ImportError, KeyboardInterrupt, RuntimeError


Một mệnh đề try có thể đi kèm 1 hay nhiều except:

# https://docs.python.org/2/tutorial/errors.html#handling-exceptions
import sys

try:
    with open('filename') as f:
        f_content = f.readlines()
        i = int(f_content.strip())
except IOError as e:
    print "I/O error({0}): {1}".format(e.errno, e.strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise

Hoặc bắt nhiều exceptions một lúc:

try:
    with open('filename') as f:
        f_content = f.readlines()
    printb
except (IOError, NameError) as e:
    print str(e)

Bẫy trên sẽ bắt cả lỗi IOErrorNameError.

Ngoài ra có thể thực hiện lệnh else trong trường hợp lệnh không có exception sinh ra khi thực hiện lệnh trong try:

# https://docs.python.org/2/tutorial/errors.html#handling-exceptions
for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'Cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()

Trong trường hợp lệnh trong mệnh đề try đang được thực hiện thì xảy ra lỗi, chương trình khi đó sẽ nhảy tới thực hiện lệnh trong mệnh đề except, có thể việc một lệnh nào đó nằm mệnh đề try chưa được thực hiện hết khiến cho phần mềm có thể bị lỗi sau đó. Khi đó bạn cần dùng đến finally.

try:
    f = open('filename','r')
    try:
        f_content = f.readline()
        i = int(f_content.strip())
    finally:
        f.close()
except IOError as e:
    print str(e)

Trong trường hợp đọc lỗi, file f vẫn sẽ được đóng lại trong finally. Chú ý sự khác biệt khi sử dụng của elsefinally: lệnh trong else chỉ được gọi khi không có lỗi xảy ra, lệnh trongfinally được gọi khi có lỗi xảy ra.


Tự định nghĩa Exceptions

Ngoài các exceptions được cung cấp sẵn, Python cũng cho phép lập trình viên tự định nghĩa các exceptions để sử dụng. Ví dụ sau đây là một đoạn source code sử dụng thư viện selenium:

# import ...
from selenium.common.exceptions import TimeoutException

try:
    myElem = WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'IdOfMyElement')))
    print "Page is ready!"
except TimeoutException:
    print "Loading took too much time!"

Ở đây, exception TimeoutException được định nghĩa thêm trong thư viện selenium để xác định khi một tác vụ bị timeout.

Người dùng có thể định nghĩa các exceptions như vậy bằng cách tạo một class mới kế thừa, một cách trực tiếp hay gián tiếp, từ class Exception. Hầu hết các exceptions có sẵn cũng được tạo ra từ class này.

Ví dụ sau thực hiện việc kế thừa từ class RuntimeError:

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

Một khi class đã được tạo và kế thừa đúng, chúng ta có thể sử dụng giống như khi sử dụng các exceptions sẵn có của Python:

try:
   raise NetworkError("Bad hostname")
except NetworkError,e:
   print e.args

Danh sách Exceptions

BaseException

 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |         +-- WindowsError (Windows)
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
      |    +-- ImportError
      |    +-- LookupError
      |    |    +-- IndexError
      |    |    +-- KeyError
      |    +-- MemoryError
      |    +-- NameError
      |    |    +-- UnboundLocalError
      |    +-- ReferenceError
      |    +-- RuntimeError
      |    |    +-- NotImplementedError
      |    +-- SyntaxError
      |    |    +-- IndentationError
      |    |         +-- TabError
      |    +-- SystemError
      |    +-- TypeError
      |    +-- ValueError
      |         +-- UnicodeError
      |              +-- UnicodeDecodeError
      |              +-- UnicodeEncodeError
      |              +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
  +-- ImportWarning
  +-- UnicodeWarning
  +-- BytesWarning

Tham khảo:

tags: python2, python3