如何从包的__init__中引发自定义异常?
我有一个包,里面有个文件叫 __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 个回答
这里似乎有点尴尬。
如果一个自定义的异常类在其他模块里根本不会被重用,那创建它真的有用吗?如果每个人都这么做,最后每个模块都会定义自己不同的(而且可能不兼容的)PythonVersionError类。
为什么不使用一个标准的现有异常呢?对于这个情况,我可能会选择一个标准的RuntimeError异常。
好吧,我知道你不想听这个答案,但无论如何,我还是说了。
如果我真的想这么做,至少我会把PythonVersionException类定义为检查代码的本地实例,这样就不会污染模块的命名空间或者其他文件的全局命名空间。
看起来你这个异常可能不会被任何用户使用——除非这个模块是你在构建一个更大系统时,其他模块要用到的。我觉得在这里不需要自定义异常。
其实自定义异常带来的好处不多,除了错误信息。任何想要导入你模块的模块都需要知道这个异常,才能捕获它,不然程序就会停止并显示回溯信息。既然要知道这个异常,它就得导入你的模块,结果还是会崩溃并显示回溯信息——用户可以在那时看到错误信息。
至于错误信息,简单的“异常”提示说是Python版本不正确,和任何自定义异常一样有效。
从技术角度看,Python需要在抛出PythonVersionError
之前知道这个异常:你需要把相关代码放在if
块之前。
最后,如果你确实在构建一个更大的系统,其他部分可能会尝试捕获PythonVersionError
,那么正确的做法是把它放在自己的文件或模块中,这样就可以让抛出这个异常的模块和任何导入它的模块都能使用。