当然,最简单的解决方案是简单地将可选依赖项导入到需要它们的函数体中。但永远正确的PEP 8 https://www.python.org/dev/peps/pep-0008/#imports says:
导入始终放在文件顶部,紧接在任何模块之后
注释和文档字符串,以及模块全局变量和常量之前。
不想违背 python 大师的良好愿望,我采取以下方法,它有几个好处......
首先,使用 try- except 导入
说一下我的一个功能foo
needs numpy
,我想让它成为一个可选的依赖项。在模块的顶部,我放置了:
try:
import numpy as _numpy
except ImportError:
_has_numpy = False
else:
_has_numpy = True
这里(在 except 块中)是打印警告的地方,最好使用warnings https://docs.python.org/2/library/warnings.html#module-warnings module.
然后在函数中抛出异常
如果用户打电话怎么办foo
并且没有numpy?我在那里抛出异常并记录此行为。
def foo(x):
"""Requires numpy."""
if not _has_numpy:
raise ImportError("numpy is required to do this.")
...
或者,您可以使用装饰器并将其应用于需要该依赖项的任何函数:
@requires_numpy
def foo(x):
...
这样做的好处是可以防止代码重复。
并将其作为可选依赖项添加到安装脚本中
如果您要分发代码,请了解如何将额外的依赖项添加到安装配置中。例如,与setuptools
,我可以写:
install_requires = ["networkx"],
extras_require = {
"numpy": ["numpy"],
"sklearn": ["scikit-learn"]}
这指定了networkx
在安装时绝对需要,但是我的模块的额外功能需要numpy
and sklearn
,这是可选的。
使用这种方法,以下是您的具体问题的答案:
我们可以简单地将可选依赖项添加到安装工具的所需依赖项列表中。在上面的例子中,我们移动numpy
to install_requires
。所有代码检查是否存在numpy
然后可以将其删除,但保留它不会导致程序中断。
只需删除对以前需要它的任何函数中的依赖项的检查即可。如果您使用装饰器实现了依赖性检查,则只需更改它即可使其简单地传递原始函数而不改变。
这种方法的好处是,将所有导入都放在模块的顶部,这样我就可以一目了然地看到什么是必需的,什么是可选的。