7.1 Tạo ngoại lệ tùy chỉnh
Thỉnh thoảng các ngoại lệ tiêu chuẩn trong Python không hoàn toàn đáp ứng
nhu cầu của ứng dụng của bạn. Trong những trường hợp đó, bạn có thể tạo
ngoại lệ của riêng mình bằng cách thừa kế chúng từ lớp cơ bản
Exception
hoặc bất kỳ lớp ngoại lệ thích hợp nào khác.
Các nguyên tắc cơ bản để tạo ngoại lệ tùy chỉnh
Việc tạo ngoại lệ tùy chỉnh bao gồm việc định nghĩa
một lớp mới thừa kế từ lớp cơ bản
Exception
. Bạn có thể thêm các phương thức và
thuộc tính của riêng mình vào lớp ngoại lệ của bạn để cung cấp
thông tin chi tiết về lỗi.
Ví dụ tạo ngoại lệ tùy chỉnh đơn giản
Bước 1: Định nghĩa ngoại lệ tùy chỉnh
class MyCustomError(Exception):
"""Lớp dành cho ngoại lệ tùy chỉnh."""
pass
Bước 2: Sử dụng ngoại lệ tùy chỉnh
def check_value(value):
if value < 0:
raise MyCustomError("Giá trị không được nhỏ hơn không")
try:
check_value(-1)
except MyCustomError as e:
print(f"Đã xảy ra ngoại lệ tùy chỉnh: {e}")
Rất đơn giản. Điều quan trọng là ngoại lệ của bạn được thừa kế từ lớp Exception
hoặc một trong số các lớp con của nó.
7.2 Tạo ngoại lệ với các thuộc tính bổ sung
Bạn có thể thêm thuộc tính và phương thức vào lớp ngoại lệ của bạn để truyền tải thông tin bổ sung về lỗi đã xảy ra.
Ví dụ:
class NegativeValueError( Exception ):
"""Lớp dành cho ngoại lệ tùy chỉnh khi giá trị âm."""
def __init__(self, value, message = "Giá trị không được nhỏ hơn không"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
Sử dụng ngoại lệ với các thuộc tính bổ sung
def check_value(value):
if value < 0:
raise NegativeValueError(value)
try:
check_value(-1)
except NegativeValueError as e:
print(f"Đã xảy ra ngoại lệ tùy chỉnh: {e}")
Ngoại lệ của chúng ta là một lớp, được thừa kế từ lớp Exception
. Do đó, bạn có thể làm tất cả những thứ mà bạn làm với
bất kỳ lớp nào khác: thêm thuộc tính, phương thức, tham số khởi tạo, v.v.
Tất cả vì sự tiện lợi của bạn, và của những lập trình viên sẽ bắt ngoại lệ của bạn.
7.3 Tạo cấu trúc phân cấp cho ngoại lệ tùy chỉnh
Đối với những ứng dụng phức tạp hơn, việc tạo cấu trúc phân cấp ngoại lệ tùy chỉnh là hữu ích. Điều này cho phép nhóm các ngoại lệ có liên quan và đơn giản hóa cách xử lý chúng.
Ví dụ:
class ApplicationError(Exception):
"""Lớp cơ bản cho tất cả ngoại lệ của ứng dụng."""
pass
class NegativeValueError(ApplicationError):
"""Lớp dành cho ngoại lệ tùy chỉnh khi giá trị âm."""
def __init__(self, value, message="Giá trị không được nhỏ hơn không"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
class ValueTooLargeError(ApplicationError):
"""Lớp dành cho ngoại lệ tùy chỉnh khi giá trị quá lớn."""
def __init__(self, value, message="Giá trị quá lớn"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
Sử dụng cấu trúc phân cấp ngoại lệ tùy chỉnh
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except NegativeValueError as e:
print(f"Đã xảy ra ngoại lệ: {e}")
except ValueTooLargeError as e:
print(f"Đã xảy ra ngoại lệ: {e}")
except ApplicationError as e:
print(f"Đã xảy ra ngoại lệ chung ứng dụng: {e}")
7.4 Thứ tự bắt ngoại lệ
Khi bắt ngoại lệ, đặc biệt là từ một cấu trúc phân cấp, điều quan trọng là phải chỉ định thứ tự đúng. Mặc dù mã trong
các khối except
không bao giờ được thực hiện đồng thời, nhưng điều quan trọng là lớp cơ bản của ngoại lệ có thể
bắt tất cả các ngoại lệ của các lớp con của nó.
Ví dụ, mã sau:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except ApplicationError as e: # bắt các ngoại lệ thuộc loại ApplicationError và tất cả các con của nó
print(f"Đã xảy ra ngoại lệ chung ứng dụng: {e}")
Trong khối except
, sẽ bắt các ngoại lệ thuộc loại ApplicationError
và tất cả các lớp con của nó.
Vì tất cả các ngoại lệ đều là lớp con của lớp Exception
, do đó mã này sẽ bắt tất cả các ngoại lệ:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except Exception as e:
print(f"Bắt tất cả các ngoại lệ: {e}")
except ApplicationError as e: # Mã này sẽ không bao giờ được thực hiện
print(f"Đã xảy ra ngoại lệ chung ứng dụng: {e}")
Bắt ngoại lệ trong khối except ApplicationError
sẽ không bao giờ xảy ra, vì khối except Exception
bắt
tất cả các ngoại lệ thuộc loại Exception
và các lớp con của nó.
Giải pháp
Vì vậy, việc bắt ngoại lệ nên được thực hiện theo thứ tự ngược với thừa kế: càng gần lớp Exception
, càng nằm dưới.
Ví dụ:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except NegativeValueError as e:
print(f"Đã xảy ra ngoại lệ: {e}")
except ApplicationError as e:
print(f"Đã xảy ra ngoại lệ chung ứng dụng: {e}")
except Exception as e:
print(f"Bắt tất cả các ngoại lệ: {e}")
Trong ví dụ này, các khối except
được đặt theo thứ tự phù hợp với cấu trúc phân cấp thừa kế của chúng:
trước tiên bắt các ngoại lệ cụ thể hơn như NegativeValueError
, sau đó mới đến các ngoại lệ chung hơn như ApplicationError
.
Điều này cho phép xử lý ngoại lệ một cách chính xác và tránh các tình huống khi một bộ xử lý chung hơn bắt một ngoại lệ trước khi các khối except
chuyên biệt hơn có cơ hội xử lý nó.
GO TO FULL VERSION