Python3 中构建模块异常的最佳实践
Best practice for structuring module exceptions in Python3
假设我有一个文件夹结构像这样的项目。
/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.py
模块定义了自己的异常并导入了可能从 helpers.py
.
引发异常的方法
# /projects/main.py
from project.__helpers.helpers import some_function_that_raises
class MainException(Exception):
pass
现在,我不希望用户在想要捕获该异常时必须执行 from project.__helpers.helpers import HelperException
。能够从引发异常的 public 模块导入异常会更有意义。
但我不能只将 HelperException
移动到 main.py
,这会创建循环导入。
允许用户从 main.py
导入所有异常而在 /__helpers
中引发的异常的最佳方法是什么?
这是我想出的解决方案。
这个想法基本上是将所有异常放在一个可以导入的文件中,然后将它们全部导入 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
然后我们可以从该文件中导入异常,而没有循环依赖的风险。
最后我们在 main.py
中定义 __all__
以明确表示要导入异常。
# /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 *
时将导入的内容。因此,这既将所需的行为扩展到 import star,又明确表示我们希望从该文件导入异常。
另请注意,某些 IDE 甚至会将 __all__
中的 'HelperException'
视为对 HelperException
的引用,并且不会因未使用的导入而打扰您。这就是让我认为这是正确方法的原因。
假设我有一个文件夹结构像这样的项目。
/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.py
模块定义了自己的异常并导入了可能从 helpers.py
.
# /projects/main.py
from project.__helpers.helpers import some_function_that_raises
class MainException(Exception):
pass
现在,我不希望用户在想要捕获该异常时必须执行 from project.__helpers.helpers import HelperException
。能够从引发异常的 public 模块导入异常会更有意义。
但我不能只将 HelperException
移动到 main.py
,这会创建循环导入。
允许用户从 main.py
导入所有异常而在 /__helpers
中引发的异常的最佳方法是什么?
这是我想出的解决方案。
这个想法基本上是将所有异常放在一个可以导入的文件中,然后将它们全部导入 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
然后我们可以从该文件中导入异常,而没有循环依赖的风险。
最后我们在 main.py
中定义 __all__
以明确表示要导入异常。
# /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 *
时将导入的内容。因此,这既将所需的行为扩展到 import star,又明确表示我们希望从该文件导入异常。
另请注意,某些 IDE 甚至会将 __all__
中的 'HelperException'
视为对 HelperException
的引用,并且不会因未使用的导入而打扰您。这就是让我认为这是正确方法的原因。