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

Oli*_*çon 6 python exception circular-dependency python-3.x

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

/project
    __init__.py
    main.py
    /__helpers
        __init__.py
        helpers.py
        ...
Run Code Online (Sandbox Code Playgroud)

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

# /project/__helpers/helpers.py

class HelperException(Exception):
    pass

def some_function_that_raises():
    raise HelperException
Run Code Online (Sandbox Code Playgroud)

另一方面,我的main.py模块定义了自己的异常并导入了可能从helpers.py.

# /projects/main.py

from project.__helpers.helpers import some_function_that_raises

class MainException(Exception):
    pass
Run Code Online (Sandbox Code Playgroud)

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

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

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

Oli*_*çon 4

这是我想出的解决方案。

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

这是新的文件结构

/project
    __init__.py
    main.py
    /__helpers
        __init__.py
        exceptions.py
        helpers.py
        ...
Run Code Online (Sandbox Code Playgroud)

这是exceptions.py文件。

# /project/__helpers/exceptions.py

class MainException(Exception):
    pass

# Note that this also allows us to inherit between exceptions
class HelperException(MainException):
    pass
Run Code Online (Sandbox Code Playgroud)

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

最后,我们定义__all__inmain.py来明确要导入异常。

# /projects/main.py

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

__all__ = ['MainException', 'HelperException', ...]
Run Code Online (Sandbox Code Playgroud)

作为提醒,__all__定义语句将导入的内容from project import *。因此,这既扩展了所需的行为以导入 star,又明确表明我们希望从该文件导入异常。

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