Cài đặt
Tôi thường gặp khó khăn trong việc xác định thời điểm và cách sử dụng ngoại lệ. Hãy xem xét một ví dụ đơn giản: giả sử tôi đang quét một trang web, nói " http://www.abevigoda.com/ ", để xác định xem Abe Vigoda có còn sống không. Để làm điều này, tất cả những gì chúng ta cần làm là tải xuống trang và tìm kiếm lần xuất hiện cụm từ "Abe Vigoda". Chúng tôi trả lại sự xuất hiện đầu tiên, vì điều đó bao gồm tình trạng của Abe. Về mặt khái niệm, nó sẽ trông như thế này:
def get_abe_status(url):
# download the page
page = download_page(url)
# get all mentions of Abe Vigoda
hits = page.find_all_mentions("Abe Vigoda")
# parse the first hit for his status
status = parse_abe_status(hits[0])
# he's either alive or dead
return status == "alive"
Trường hợp parse_abe_status(s)
lấy một chuỗi có dạng "Abe Vigoda là một cái gì đó " và trả về phần " cái gì đó ".
Trước khi bạn lập luận rằng có nhiều cách tốt hơn và mạnh mẽ hơn để quét trang này cho trạng thái của Abe, hãy nhớ rằng đây chỉ là một ví dụ đơn giản và dễ hiểu được sử dụng để làm nổi bật một tình huống phổ biến mà tôi gặp phải.
Bây giờ, mã này có thể gặp vấn đề ở đâu? Trong số các lỗi khác, một số lỗi "dự kiến" là:
download_page
có thể không tải được trang và némIOError
.- URL có thể không trỏ đến trang bên phải hoặc trang được tải xuống không chính xác và do đó không có lần truy cập nào.
hits
là danh sách trống, sau đó. - Trang web đã bị thay đổi, có thể làm cho các giả định của chúng tôi về trang bị sai. Có thể chúng tôi mong đợi 4 đề cập đến Abe Vigoda, nhưng bây giờ chúng tôi tìm thấy 5.
- Vì một số lý do,
hits[0]
có thể không phải là một chuỗi có dạng "Abe Vigoda là một cái gì đó ", và vì vậy nó không thể được phân tích cú pháp chính xác.
Trường hợp đầu tiên thực sự không phải là vấn đề đối với tôi: một cú IOError
ném và có thể được xử lý bởi người gọi chức năng của tôi. Vì vậy, hãy xem xét các trường hợp khác và làm thế nào tôi có thể xử lý chúng. Nhưng trước tiên, hãy giả sử rằng chúng ta thực hiện parse_abe_status
theo cách ngu ngốc nhất có thể:
def parse_abe_status(s):
return s[13:]
Cụ thể, nó không thực hiện bất kỳ kiểm tra lỗi. Bây giờ, vào các tùy chọn:
Cách 1: Trả lại None
Tôi có thể nói với người gọi rằng có gì đó không ổn bằng cách quay lại None
:
def get_abe_status(url):
# download the page
page = download_page(url)
# get all mentions of Abe Vigoda
hits = page.find_all_mentions("Abe Vigoda")
if not hits:
return None
# parse the first hit for his status
status = parse_abe_status(hits[0])
# he's either alive or dead
return status == "alive"
Nếu người gọi nhận được None
từ chức năng của tôi, ông nên cho rằng không có đề cập đến Abe Vigoda, và do đó một cái gì đó đã đi sai. Nhưng điều này khá mơ hồ, phải không? Và nó không giúp ích gì cho trường hợp hits[0]
không như chúng ta nghĩ.
Mặt khác, chúng ta có thể đưa ra một số ngoại lệ:
Tùy chọn 2: Sử dụng ngoại lệ
Nếu hits
trống, một IndexError
sẽ được ném khi chúng ta cố gắng hits[0]
. Nhưng người gọi không nên được yêu cầu xử lý một IndexError
chức năng của tôi, vì anh ta không biết nó IndexError
đến từ đâu; nó có thể bị ném bởi find_all_mentions
, vì tất cả những gì anh biết. Vì vậy, chúng tôi sẽ tạo một lớp ngoại lệ tùy chỉnh để xử lý việc này:
class NotFoundError(Exception):
"""Throw this when something can't be found on a page."""
def get_abe_status(url):
# download the page
page = download_page(url)
# get all mentions of Abe Vigoda
hits = page.find_all_mentions("Abe Vigoda")
try:
hits[0]
except IndexError:
raise NotFoundError("No mentions found.")
# parse the first hit for his status
status = parse_abe_status(hits[0])
# he's either alive or dead
return status == "alive"
Bây giờ nếu trang đã thay đổi và có số lần truy cập không mong muốn thì sao? Đây không phải là thảm họa, vì mã vẫn có thể làm việc, nhưng một người gọi có thể muốn có thêm cẩn thận, hoặc ông có thể muốn ghi lại một cảnh báo. Vì vậy, tôi sẽ đưa ra một cảnh báo:
class NotFoundError(Exception):
"""Throw this when something can't be found on a page."""
def get_abe_status(url):
# download the page
page = download_page(url)
# get all mentions of Abe Vigoda
hits = page.find_all_mentions("Abe Vigoda")
try:
hits[0]
except IndexError:
raise NotFoundError("No mentions found.")
# say we expect four hits...
if len(hits) != 4:
raise Warning("An unexpected number of hits.")
logger.warning("An unexpected number of hits.")
# parse the first hit for his status
status = parse_abe_status(hits[0])
# he's either alive or dead
return status == "alive"
Cuối cùng, chúng ta có thể thấy rằng status
không còn sống hay đã chết. Có thể, vì một số lý do kỳ lạ, hôm nay hóa ra là như vậy comatose
. Sau đó tôi không muốn quay lại False
, vì điều đó ngụ ý rằng Abe đã chết. Tôi nên làm gì ở đây? Ném một ngoại lệ, có lẽ. Nhưng loại nào? Tôi có nên tạo một lớp ngoại lệ tùy chỉnh?
class NotFoundError(Exception):
"""Throw this when something can't be found on a page."""
def get_abe_status(url):
# download the page
page = download_page(url)
# get all mentions of Abe Vigoda
hits = page.find_all_mentions("Abe Vigoda")
try:
hits[0]
except IndexError:
raise NotFoundError("No mentions found.")
# say we expect four hits...
if len(hits) != 4:
raise Warning("An unexpected number of hits.")
logger.warning("An unexpected number of hits.")
# parse the first hit for his status
status = parse_abe_status(hits[0])
if status not in ['alive', 'dead']:
raise SomeTypeOfError("Status is an unexpected value.")
# he's either alive or dead
return status == "alive"
Lựa chọn 3: Một nơi nào đó ở giữa
Tôi nghĩ rằng phương pháp thứ hai, với các ngoại lệ, là tốt hơn, nhưng tôi không chắc liệu tôi có sử dụng ngoại lệ một cách chính xác trong đó không. Tôi tò mò muốn xem các lập trình viên giàu kinh nghiệm hơn sẽ xử lý việc này như thế nào.