Mục tiêu
Phần I: Hướng dẫn thực hành
Lab09.01: Exception là gì?
Trước hết chúng ta hãy xem một ví dụ minh họa sau:
Trong ví dụ này có một đoạn code lỗi nguyên nhân do phép chia cho 0. Việc chia cho 0 gây ra ngoại lệ: ZeroDivisionError
helloExceptionExample.py
print ("Three")
# Phép chia này không vấn đề.
value = 10 / 2
print ("Two")
# Phép chia này không vấn đề.
value = 10 / 1
print ("One")
d = 0
# Phép chia này có vấn đề, cho cho 0
# Một lỗi được phát ra tại đây.
value = 10 / d
# Dòng mã dưới đây sẽ không được thực thi.
print ("Let's go!")
Kết quả: khi chạy ví dụ trên,
Hãy xem luồng đi của chương trình qua hình minh họa dưới đây.
Chúng ta sẽ sửa code đoạn chương trình trên như sau:
print ("Three")
value = 10 / 2
print ("Two")
value = 10 / 1
print ("One")
d = 0
try :
# Phép chia này có vấn đề, chia cho 0.
# Một lỗi được phát ra tại đây (ZeroDivisionError).
value = 10 / d
print ("value = ", value)
except ZeroDivisionError as e :
print ("Error: ", str(e) )
print ("Ignore to continue ...")
print ("Let's go!")
Kết quả:
Three
Two
One
Error: division by zero
Ignore to continue ...
Let's go!
Chúng ta sẽ giải thích bằng hình minh họa dưới đây về luồng đi của chương trình.
Lab09.02: Sơ đồ phân cấp
Sơ đồ phân cấp của các ngoại lệ trong Python
Các Exception sẵn có của Python thông thường được bắt nguồn (derived) từ BaseException (Mở rộng từ BaseException). Trong khi đó các Exception của người dùng (lập trình viên) nên thừa kế từ lớp Exception hoặc từ các lớp con của nó.
Lab09.03: Bắt ngoại lệ thông qua try - except
Hàm checkAge để kiểm tra tuổi, nếu tuổi nhỏ hơn 18 hoặc lớn hơn 40 một ngoại lệ sẽ được ném ra.
# ageException.py
"""
Hàm checkAge để kiểm tra tuổi, nếu tuổi nhỏ hơn 18 hoặc lớn hơn 40 một ngoại lệ sẽ được ném ra.
# ageException.py
"""
# Tạo lớp AgeException kế thừa từ Exception
class AgeException(Exception):
def __init__(self, msg, age ):
super().__init__(msg)
self.age = age
# end of class AgeException
# Tạo lớp TooYoungException kế thừa lớp AgeException
class TooYoungException(AgeException):
def __init__(self, msg, age):
super().__init__(msg, age)
# end of class TooYoungException
# Tạo lớp TooOldException kế thừa lớp AgeException
class TooOldException(AgeException):
def __init__(self, msg, age):
super().__init__(msg, age)
# end of class TooOldException
# Hàm kiểm tra tuổi, nó có thể ném ra ngoại lệ.
def checkAge(age):
if (age < 18) :
# Nếu tuổi nhỏ hơn 18, một ngoại lệ sẽ bị ném ra.
# Hàm sẽ bị kết thúc tại đây.
raise TooYoungException("Age " + str(age) + " too young", age)
elif (age > 40) :
# Nếu tuổi lớn hơn 40, một ngoại lệ sẽ bị ném ra
# Hàm sẽ bị kết thúc tại đây.
raise TooOldException("Age " + str(age) + " too old", age)
# Nếu tuổi nằm trong khoảng 18-40.
# Đoạn code này sẽ được thực thi.
print ("Age " + str(age) + " OK!")
# end of file ageException.py
# tryExceptTest.py
# tryExceptTest.py
import ageException
from ageException import AgeException
from ageException import TooYoungException
from ageException import TooOldException
print ("Start Recruiting ...")
# Input age
age = int(input("input your age:"))
print ("Check your Age ", age)
try :
ageException.checkAge(age)
print ("You pass!")
except TooYoungException as e :
print("You are too young, not pass!")
print("Cause message: ", str(e) )
print("Invalid age: ", e.age)
except TooOldException as e :
print ("You are too old, not pass!")
print ("Cause message: ", str(e) )
print("Invalid age: ", e.age)
# end of file tryExceptTest.py
Kết quả: thực thi chương trình
Start Recruiting ...
input your age:10
Check your Age 10
You are too young, not pass!
Cause message: Age 10 too young
Invalid age: 10
Start Recruiting ...
input your age:20
Check your Age 20
Age 20 OK!
You pass!
Start Recruiting ...
input your age:50
Check your Age 50
You are too old, not pass!
Cause message: Age 50 too old
Invalid age: 50
Ví dụ dưới đây, chúng ta sẽ gộp bắt các ngoại lệ thông qua ngoại lệ ở cấp cao hơn. Ở cấp cao hơn nó sẽ bắt được ngoại lệ đó và tất cả các ngoại lệ con.
# tryExceptTest2.py
import ageException
from ageException import AgeException
from ageException import TooYoungException
from ageException import TooOldException
print ("Start Recruiting ...")
# Input age
age = int(input("input your age:"))
print ("Check your Age ", age)
try :
ageException.checkAge(age)
print ("You pass!")
except AgeException as e :
print("You are not pass!")
print("type(e): ", type(e) )
print("Cause message: ", str(e) )
print("Invalid age: ", e.age)
# End of file tryExceptTest2.py
Chạy chương trình:
Start Recruiting ...
input your age:22
Check your Age 22
Age 22 OK!
You pass!
Start Recruiting ...
input your age:12
Check your Age 12
You are not pass!
type(e):
Cause message: Age 12 too young
Invalid age: 12
Lab09.04: Khối try-expert-finally
Các ví dụ trên chúng ta đã làm quen với việc bắt ngoại lệ thông qua khối try-except.
Việc xử lý ngoại lệ đầy đủ là try-except-finally.
Khối finally luôn được thực thi bất kể ngoại lệ có xẩy ra tại khối try hay không.
Cú pháp:
try :
# Làm gì đó tại đây.
except Exception1 as e :
# Làm gì đó tại đây.
except Exception2 as e :
# Làm gì đó tại đây.
finally :
# Khối finally luôn luôn được thực thi.
# Làm gì đó tại đây.
Ví dụ:
# Định nghĩa hàm
def toInteger(text) :
try :
print ("-- Begin parse text: ", text)
# Một ngoại lệ có thể bị ném ra tại đây (ValueError).
value = int(text)
return value
except ValueError as e :
# Trường hợp 'text' không là một số.
# Khối 'except' sẽ được thực thi.
print ("ValueError message: ", str(e))
print ("type(e): ", type(e))
# Trả về 0 nếu xuất hiện lỗi ValueError.
return 0
finally :
print ("-- End parse text: " + text)
# Test
text = "001234A2"
value = toInteger(text)
print ("Value= ", value)
text = "12345"
value = toInteger(text)
print ("Value= ", value)
Kết quả:
-- Begin parse text: 001234A2
ValueError message: invalid literal for int() with base 10: '001234A2'
type(e):
-- End parse text: 001234A2
Value= 0
-- Begin parse text: 12345
-- End parse text: 12345
Value= 12345
Sơ đồ luồng đi của chương trình. Khối finally luôn được thực thi.
Lab09.05: Lệnh pass
Nếu bạn không muốn xử lý gì trong khối 'except' hoặc 'finally' bạn có thể sử dụng lệnh 'pass' (pass statement). Lệnh pass không làm bất cứ điều gì, nó giống như một lệnh null.
# passStatementExample.py
print ("Three")
try :
value = 10 / 0
except Exception as e:
pass
print ("Two")
print ("One")
print ("Let's go")
# End of file passStatementExample.py
Kết quả:
Three
Two
One
Let's go
Lab09.06: Ném tiếp ngoại lệ
Trong khi xử lý ngoại lệ bạn có thể bắt ngoại lệ đó và xử lý hoặc có thể ném tiếp (rethrow) nó ra vòng ngoài.
# reRaiseExceptionDemo1.py
def checkScore(score) :
if score < 0 or score > 100:
raise Exception("Invalid Score " + str(score) )
# End of function checkScore
def checkPlayer(name, score):
try :
checkScore(score)
except Exception as e :
print ("Something invalid with player: ",name, ' >> ', str(e) )
# re throw exception.
raise
# End of function checkPlayer
# ------------------------------------------
# Test
checkPlayer("Chung Trịnh", 101)
Kết quả:
Exception has occurred: Exception
Invalid Score 101
File "C:\Devmaster.edu.vn\Python\LabGuide09\reRaiseExceptionDemo1.py", line 6, in checkScore raise Exception("Invalid Score " + str(score) ) File "C:\Devmaster.edu.vn\Python\LabGuide09\reRaiseExceptionDemo1.py", line 14, in checkPlayer checkScore(score) File "C:\Devmaster.edu.vn\Python\LabGuide09\reRaiseExceptionDemo1.py", line 27, in checkPlayer("Chung Trịnh", 101)
Ví dụ, bắt ngoại lệ và ném tiếp (rethrow) bởi một ngoại lệ khác.
# reRaiseExceptionDemo2.py
# reRaiseExceptionDemo2.py
def checkScore(score) :
if score < 0 or score > 100:
raise Exception("Invalid Score " + str(score) )
# End of function checkScore
def checkPlayer(name, score):
try :
checkScore(score)
except Exception as e :
print ("Something invalid with player: ",name, ' >> ', str(e) )
# throw new exception.
raise Exception("Something invalid with player: "+ name + " >> "+ str(e))
# End of function checkPlayer
# ------------------------------------------
checkPlayer("Chung Trịnh", 101)
Kết quả:
Lab09.07: Gói một Exception trong một Exception khác
Python cho phép bắt ngoại lệ, và ném ra một ngoại lệ mới, ngoại lệ mới có thể lưu trữ thông tin của ngoại lệ ban đầu, mà bạn có thể truy cập thông qua thuộc tính __cause__
Cú pháp:
try :
# Làm gì đó tại đây...
except Exception as e :
raise OtherException("Message...") from e
Ví dụ:
# wrapExceptionDemo.py
# Ngoại lệ giới tính.
class GenderException(Exception):
def __init__(self, msg):
super().__init__(msg)
# Ngoại lệ ngôn ngữ.
class LanguageException(Exception):
def __init__(self, msg):
super().__init__(msg)
# Ngoại lệ cá nhân.
class PersonException(Exception):
def __init__(self, msg):
super().__init__(msg)
# Hàm này có thể ném ra GenderException.
def checkGender(gender):
if gender != 'Female' :
raise GenderException("Accept female only")
# Hàm này có thể ném ra LanguageException.
def checkLanguage(language):
if language != 'English' :
raise LanguageException("Accept english language only")
# Hàm checkPerson
def checkPerson(name, gender, language):
try :
# Có thể ném ra GenderException.
checkGender(gender)
# Có thể ném ra LanguageException.
checkLanguage(language)
except Exception as e:
# Bắt exception và ném ra ngoại lệ khác.
# Ngoại lệ mới có thông tin __cause__ = e.
raise PersonException(name + " does not pass") from e
# --------------------------------------------------------
try :
checkPerson("Devmaster", "Female", "Vietnamese")
except PersonException as e:
print ("Error message: ", str(e) )
# GenderException hoặc LanguageException
cause = e.__cause__
print ('e.__cause__: ', repr(cause))
print ("type(cause): " , type(cause) )
print (" ------------------ ")
if type(cause) is GenderException :
print ("Gender exception: ", cause)
elif type(cause) is LanguageException:
print ("Language exception: ", cause)
# --------------------------------------------------------
Kết quả:
Error message: Devmaster does not pass
e.__cause__: LanguageException('Accept english language only')
type(cause):
------------------
Language exception: Accept english language only
CUỘC SỐNG VỐN KHÔNG CÔNG BẰNG
HÃY TẬP QUEN DẦN VỚI ĐIỀU ĐÓ
Bill Gates
Phần II Bài tập tự làm
Bài 01: Viết chương trình python minh họa việc sử dụng các ngoại lệ:
HẾT