避免尝试 - 除了嵌套

时间:2014-07-02 19:27:05

标签: python exception-handling nested try-catch

鉴于文件类型未知的文件,我想用多个处理程序之一打开该文件。如果无法打开文件,则每个处理程序都会引发异常。 我想尝试所有这些,如果没有成功,就提出异常。

我想出的设计是

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:
            ...

这个级联似乎不是正确的方法。

有什么建议吗?

4 个答案:

答案 0 :(得分:5)

也许您可以对所有处理程序进行分组并在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

答案 1 :(得分:1)

完全无法检查?

>>> 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并获得有意义的代码,或者阅读文件路径并使用类型检查器,甚至只是拆分文件名来获取扩展名...... {{1 }}

答案 2 :(得分:0)

与其他人一样,我也建议使用循环,但使用更严格的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)

答案 3 :(得分:0)

您可以使用上下文管理器:

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)