簡體   English   中英

避免嘗試 - 除了嵌套

[英]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/excepteafp在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM