在 Python3 中构建模块异常的最佳实践

Best practice for structuring module exceptions in Python3

提问人:Olivier Melançon 提问时间:1/5/2018 最后编辑:Olivier Melançon 更新时间:11/18/2023 访问量:2612

问:

假设我有一个文件夹结构这样的项目。

/project
    __init__.py
    main.py
    /__helpers
        __init__.py
        helpers.py
        ...

该模块定义了一些异常,并包含一些引发该异常的方法。helpers.py

# /project/__helpers/helpers.py

class HelperException(Exception):
    pass

def some_function_that_raises():
    raise HelperException

另一方面,我的模块定义了自己的异常,并导入了可能引发异常的方法。main.pyhelpers.py

# /projects/main.py

from project.__helpers.helpers import some_function_that_raises

class MainException(Exception):
    pass

现在,我不希望用户在想要捕获该异常时必须这样做。能够从引发异常的公共模块导入异常会更有意义。from project.__helpers.helpers import HelperException

但我不能只是移动到 ,这将创建一个循环导入。HelperExceptionmain.py

允许用户导入所有异常的最佳方式是什么?main.py/__helpers

python-3.x 异常 循环依赖

评论


答:

4赞 Olivier Melançon 1/5/2018 #1

这是我想出的解决方案。

这个想法是将所有异常放在一个文件中,然后将它们全部导入 .为了使其简洁明了,我们定义了模块的属性。main.py__all__

下面是新的文件结构

/project
    __init__.py
    main.py
    /__helpers
        __init__.py
        exceptions.py
        helpers.py
        ...

这是文件。exceptions.py

# /project/__helpers/exceptions.py

class MainException(Exception):
    pass

# Note that this also allows us to inherit between exceptions
class HelperException(MainException):
    pass

然后,我们可以从该文件中导入异常,而无需循环依赖。

最后,我们定义 in 以明确要导入异常。__all__main.py

# /projects/main.py

from project.__helpers.helpers import some_function_that_raises
from project.__helpers.exceptions import MainException, HelperException

__all__ = ['MainException', 'HelperException', ...]

提醒一下,定义语句将导入的内容。因此,这既扩展了导入星号的所需行为,又明确了我们希望从该文件导入异常。__all__from project import *

某些 IDE 甚至会将 in 识别为对未使用的导入的引用,并且不会指示未使用的导入。这让我认为这是正确的方法。'HelperException'__all__HelperException