Mô hình xử lý ngoại lệ trong Jython
Tương tự Java, trong Jython cũng cung cấp mô hình try để thực hiện xử lý ngoại lệ (exception handling). Một số logic xử lý như sau:
try: # perform some task that may raise an exception except Exception, value: # perform some exception handling finally: # perform tasks that must always be completed (Will be performed before the exception is # raised.)
Trong logic try-exception-finally, đoạn code tiềm ẩn sẽ được thực thi bởi try, nếu có xuất hiện exception, nó sẽ được đoạn except xử lý (tương tự catch trong Java). Ví dụ:
>>> myvar = 10 >>> try: ... 1/0 ... except BaseException, e: ... global myvar ... myvar +=10 ... print "exec except block, because: ", e ... finally: ... global myvar ... myvar += 5 ... print "exec finally block." ... exec except block, because: integer division or modulo by zero exec finally block. >>> print myvar 25 >>>
Cấu trúc try-finally
Điểm khác biệt so với Java đó là Jython không bắt buộc phải có except (tương đương catch), minh chứng là cấu trúc try-finally
try: # perform some tasks that may raise an exception finally: # perform tasks that must always be completed (Will be performed before the exception is # raised.)
Ví dụ:
>>> myvar=10 >>> try: ... 1/0 ... print myvar ... finally: ... global myvar ... myvar += 30 ... print "exec finally" ... <stdin>:5: SyntaxWarning: name 'myvar' declared global after use exec finally Traceback (most recent call last): File "<stdin>", line 2, in <module> ZeroDivisionError: integer division or modulo by zero >>> print myvar 40 >>>
Cấu trúc try-except-else:
Mệnh đề else có thể được sử dụng cùng với mô hình xử lý ngoại lệ để đảm bảo rằng một số task sẽ chỉ được chạy nếu như không có exception nào trả về. Đoạn code bên trong mệnh đề else chỉ được khởi tạo nếu như không có exception nào được throw và nếu như có bất kỳ exception nào được trả về trong quá trình thực thi else thfi sẽ không thể quay về except được nữa. Ví dụ các hành động commit database sẽ được đặt trong mệnh đề else, bởi vì nếu như một vài transaction được đặt trong try thì ta sẽ không hề mong muốn có một động thái commit nào nếu như có xảy ra exception.
Cú pháp:
try: # perform some tasks that may raise an exception except: # perform some exception handling else: # perform some tasks thatwill only be performed if no exceptions are thrown Ví dụ: >>> current_status = 'init' >>> print current_status init >>> try: ... print "take some risks" ... 1/0 ... except: ... global current_status ... current_status = 'fail_and_roll_backed' ... print "roll backed" ... else: ... global current_status ... current_status = "commited" ... print "commited." ... take some risks roll backed >>> print current_status fail_and_roll_backed >>>
Ta có thể tùy chọn việc có chỉ định kiểu exception để bắt hoặc không, việc chỉ định được thực hiện ở khối except. Hoặc có thể chỉ định chung chung một khối except không kèm theo loại exception nào. Tối ưu nhất vẫn là chỉ định kiểu exception mà ta dự đoán trước và cung cấp các giải pháp xử lý nó tối ưu nhất.
Lấy thông tin từ exception trả về
Nếu như một ngoại lệ ở dạng tổng quát được trả về thì thật khó để xác định xem nguyên nhân xuất hiện nó. Xét ví dụ như sau:
>>> try: ... 8/0 ... except Exception, ex1: ... 'An error has occurred' ... 'An error has occurred'
Để lấy thông tin của ngoại lệ được sinh ra, có một số cách như sau:
dùng hàm type(exception_object) để lấy về kiểu của ngoại lệ. Ví dụ
>>> type(ex1) <type 'exceptions.ZeroDivisionError'> >>>
Hoặc sử dụng một hàm được cung cấp sẵn bởi gói sys có tên là sys.exc_info(). Ví dụ:
# Perform exception handling without explicitly naming the exception type >>> x = 10 >>> try: ... z = x / y ... except: ... print "Unexpected error: ", sys.exc_info()[0], sys.exc_info()[1] ... Unexpected error: <type 'exceptions.NameError'> name 'y' is not defined
Bắt và xử lý nhiều exception
Tương tự như cách liệt kê nhiều mệnh đề catch trong Java, ta cũng có thể ghép nhiều mệnh đề except:
>>> x = 10 >>> y = 0 >>> try: ... z = x / y ... except NameError, err1: ... print err1 ... except ZeroDivisionError, err2: ... print 'You cannot divide a number by zero!' ... You cannot divide a number by zero!
Cũng như Java, việc xử lý ngoại lệ trong Jython là một thao tác tốn kém, do đó nên cân nhắc việc này. Và nếu muốn bắt nhiều ngoại lệ, thì hãy xếp các ngoại lệ hay gặp lên trước nhất, để giảm thiểu các thao tác xử lý.
Tổ chức các cụm xử lý ngoại lệ lồng nhau
Một chương trình với nhiều cấp xử lý cũng sẽ cần tới nhiều cấp hỗ trợ bắt các ngoại lệ được sinh ra để đảm bảo toàn thể logic chương trình được chạy hết. Tương tự Java, trong Jython ta cũng có thể xây dựng một cấu trúc bắt ngoại lệ đa cấp như sau:
# Perform some division on numbers entered by keyboard
try:
# do some work
try:
x = raw_input ('Enter a number for the dividend: ')
y = raw_input('Enter a number to divisor: ')
x = int(x)
y = int(y)
except ValueError:
# handle exception and move to outer try-except
print 'You must enter a numeric value!'
z = x / y
except ZeroDivisionError:
# handle exception
print 'You cannot divide by zero!'
except TypeError:
print 'Retry and only use numeric values this time!'
else:
print 'Your quotient is: %d' % (z)
Nếu như xuất hiện ValueError exception, thì vẫn có thể có khả năng xuất hiện ZeroDivisionError, TypeError bởi nó thuộc cặp try-except bên ngoài. Nếu tất cả các except không đón nhận được ngoại lệ nào và không có ngoại lệ nào khác sinh ra, thì khối lệnh else sẽ được thực thi.
Trả về một ngoại lệ
Trong Java ta sử dụng throw/throws để trả về các ngoại lệ, trong Jython ta sử dụng raise để làm điều này. Cú pháp sử dụng raise như sau:
raise ExceptionType or String[, message[, traceback]]
Ngoại lệ được trả về có thể là ngoại lệ được xây dựng sẵn hoặc ngoại lệ tự định nghĩa.
Các vấn đề nâng cao hơn, xin vui lòng xem thêm chi tiết tại Jython exception handling
No comments:
Post a Comment