[英]Avoiding try-except nesting
給定一個未知文件類型的文件,我想用多個處理程序之一打開該文件。 如果無法打開文件,則每個處理程序都會引發異常。 我想嘗試所有這些,如果沒有成功,提出異常。
我想出的設計是
filename = 'something.something'
try:
content = open_data_file(filename)
handle_data_content(content)
except IOError:
try:
content = open_sound_file(filename)
handle_sound_content(content)
except IOError:
try:
content = open_image_file(filename)
handle_image_content(content)
except IOError:
...
這種級聯似乎不是正確的方法。
有什么建議?
也許您可以對所有處理程序進行分組並在for
循環中對它們進行評估,如果沒有成功則在最后引發異常。 您還可以繼續查看引發的異常,從中獲取一些信息,如下所示:
filename = 'something.something'
handlers = [(open_data_file, handle_data_context),
(open_sound_file, handle_sound_content),
(open_image_file, handle_image_content)
]
for o, h in handlers:
try:
o(filename)
h(filename)
break
except IOError as e:
pass
else:
# Raise the exception we got within. Also saves sub-class information.
raise e
完全沒有問題嗎?
>>> import urllib
>>> from mimetypes import MimeTypes
>>> guess = MimeTypes()
>>> path = urllib.pathname2url(target_file)
>>> opener = guess.guess_type(path)
>>> opener
('audio/ogg', None)
我知道try/except
和eafp
在Python中非常流行,但有時候愚蠢的一致性只會干擾手頭的任務。
此外,IMO的try / except循環可能不一定會因為您期望的原因而中斷,並且正如其他人指出的那樣,如果您想要查看實際發生的事情,您將需要以有意義的方式報告錯誤迭代文件切換器,直到您成功或失敗。 無論哪種方式,都會編寫內省的代碼:深入了解try / excepts並獲得有意義的代碼,或者閱讀文件路徑並使用類型檢查器,甚至只是拆分文件名以獲得擴展...... in the face of ambiguity, refuse the temptation to guess
。
與其他人一樣,我也建議使用循環,但使用更嚴格的try/except
范圍。
此外,重新提升原始異常總是更好,以便保留有關失敗的額外信息,包括追溯。
openers_handlers = [ (open_data_file, handle_data_context) ]
def open_and_handle(filename):
for i, (opener, handler) in enumerate(openers_handlers):
try:
f = opener(filename)
except IOError:
if i >= len(openers_handlers) - 1:
# all failed. re-raise the original exception
raise
else:
# try next
continue
else:
# successfully opened. handle:
return handler(f)
您可以使用上下文管理器:
class ContextManager(object):
def __init__(self, x, failure_handling):
self.x = x
self.failure_handling = failure_handling
def __enter__(self):
return self.x
def __exit__(self, exctype, excinst, exctb):
if exctype == IOError:
if self.failure_handling:
fn = self.failure_handling.pop(0)
with ContextManager(fn(filename), self.failure_handling) as context:
handle_data_content(context)
return True
filename = 'something.something'
with ContextManager(open_data_file(filename), [open_sound_file, open_image_file]) as content:
handle_data_content(content)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.