新类型的Rethrow Python异常

时间:2014-05-03 18:56:35

标签: python exception python-3.x

我有一个类NameDatabase,可以打开一个sqlite文件。好几件事 可能会出错,例如格式错误的数据库,错误的架构等。这通常会导致 异常(在我的情况下为sqlite3.Error)。

我不想让这个异常逃脱我的课程。相反,我想给 调用者我自己的异常类(推理:除了NameDatabase我也有 用于图像和GPS轨道的课程,我想向呼叫者展示一个共同的 要处理的例外情况清单。)

首先,这是一个好主意吗?第二,我最好怎么做呢?

我目前的代码:

class FileParseError(...): pass

class NameDatabase:
    def __init__(self, fname):
        self.fname = fname
        try:
            self.conn = sqlite3.connect(fname)
            # Check if we can query the DB and if the schema is ok.
            self.conn.execute('SELECT count(*) FROM names')
        except sqlite3.Error:
            raise FileParseError("Not a valid database: '%s'", fname)

这有效,但提供了双重追溯(在处理上述异常时,发生了另一个异常)。我理想的是原始的追溯,以及我自己的类型FileParseError的例外(它可以存储关于原始异常的一些信息)。

我知道我可以使用sys.exc_info()来实现这样的目标 异常处理程序并在外部重新引发异常,但看起来如此 凌乱,因为我必须在except子句中设置一个标志来记住处理 之后出错。还有更好的方法吗?

exc = None
try:
    ...
except sqlite3.Error:
    exc = sys.exc_info()
if exc:
    raise FileParseError("Invalid DB '%s': %s", fname, str(exc[1])), None, exc[2]

平台:Windows上的CPython 3.3。

类似的问题:10555671正是我现在拥有的。我正在寻找避免双追溯的东西,同时避免手动exc标志设置和再检查 - 除了。

1 个答案:

答案 0 :(得分:5)

看起来您想要将现有的新异常链接起来。可以使用PEP 3134引入的语法来完成。或者,您可以使用PEP 409中添加的语法完全抑制先前的异常。

要链接异常,请在as语句中为已捕获的异常提供except的名称,然后在from语句末尾使用名称raise 。像这样:

except sqlite3.Error as e:
    raise FileParseError("Not a valid database: '%s'", fname) from e

如果要完全禁止sqlite错误,而不是仅将其转换为其他异常类型,则可以在from None语句中使用raise

except sqlite3.Error:
    raise FileParseError("Not a valid database: '%s'", fname) from None

当上下文被抑制时,内部异常仍然可用,但它不会在回溯中打印出来。

如果您想更详细地了解异常链接的问题,您应该阅读上面链接的PEP,也可能是PEP 415,它描述了PEP 409的更新实现。