如何从包的__init__中引发自定义异常?

3 投票
2 回答
604 浏览
提问于 2025-04-16 13:15

我有一个包,里面有个文件叫 __init__.py,内容大概是这样的:

import sys

__required_python_version = (2,6, 0)

if sys.version_info < __required_python_version:
    this_version = '.'.join([str(x) for x in sys.version_info[0:3]])
    required_version = '.'.join([str(x) for x in __required_python_version])
    raise PythonVersionError(this_version, required_version)

class PythonVersionError(Exception):
    def __init__(self, this_version, required_version):
        self.this_version = this_version
        self.required_version = required_version

    def __str__(self):
        return 'Python version %s is invalid.  Must be at least %s' % (self.this_ver, self.required_ver)

虽然我知道有更优雅的方式来格式化这些版本字符串,而且我也可以用一个标准的异常来处理,但我真正想问的是,像这样做应该怎么做呢?最好的方法是把我自定义的异常放到一个单独的文件里,然后导入它吗?还是应该把版本检查放在一个函数里,让这个函数在 __init__ 被运行时执行?我只是想知道大家推荐的最佳做法是什么。

谢谢

2 个回答

2

这里似乎有点尴尬。

如果一个自定义的异常类在其他模块里根本不会被重用,那创建它真的有用吗?如果每个人都这么做,最后每个模块都会定义自己不同的(而且可能不兼容的)PythonVersionError类。

为什么不使用一个标准的现有异常呢?对于这个情况,我可能会选择一个标准的RuntimeError异常。

好吧,我知道你不想听这个答案,但无论如何,我还是说了。

如果我真的想这么做,至少我会把PythonVersionException类定义为检查代码的本地实例,这样就不会污染模块的命名空间或者其他文件的全局命名空间。

3

看起来你这个异常可能不会被任何用户使用——除非这个模块是你在构建一个更大系统时,其他模块要用到的。我觉得在这里不需要自定义异常。

其实自定义异常带来的好处不多,除了错误信息。任何想要导入你模块的模块都需要知道这个异常,才能捕获它,不然程序就会停止并显示回溯信息。既然要知道这个异常,它就得导入你的模块,结果还是会崩溃并显示回溯信息——用户可以在那时看到错误信息。

至于错误信息,简单的“异常”提示说是Python版本不正确,和任何自定义异常一样有效。

从技术角度看,Python需要在抛出PythonVersionError之前知道这个异常:你需要把相关代码放在if块之前。

最后,如果你确实在构建一个更大的系统,其他部分可能会尝试捕获PythonVersionError,那么正确的做法是把它放在自己的文件或模块中,这样就可以让抛出这个异常的模块和任何导入它的模块都能使用。

撰写回答