python - 可以在使用点而不是文件顶部导入依赖项吗?

标签 python

假设我有一个包含一堆对象的模块,这些对象都不需要第三方库。好吧,几乎没有:一个函数,称之为 asterix() ,需要第三方包。 asterix()不是模块的重点,但在需要时很方便。
仅仅为了那个功能而需要并导入整个第三方包似乎是一种耻辱。我有哪些选择?搬家asterix()到另一个模块/包或vendoring看起来很傻。
我发现快速和干净的最佳平衡是简单地在 asterix() 内进行导入。本身,可能有一些额外的 try/except 逻辑围绕它。它违反了最小意外原则和将导入放在顶部的惯例。但我告诉自己,我总是会违反一些东西。
群众智慧对此有何看法?有什么明显的我想念的吗?

def asterix(...):
    try:
        import something_special
    except ModuleNotFoundError as err:
        # do something about err (help the user out!)
    # The special code...

最佳答案

当我刚接触这门语言时,我也很想使用函数内联导入。事后看来,现在拥有 10 多年的 Python 经验,我可以告诉你,这样做通常不是一个好主意。将所有导入放在模块的顶部,除非您有充分的理由推迟它们。 内联导入隐藏依赖项。 如果有充分的理由推迟导入,请确保您有必要的日志记录和监控以了解失败的位置/时间。
我知道 "because the style guide says to"并不是一个真正令人满意的答案,所以这就是我认为主要的潜在问题:Python 中的打包和部署可能很复杂,而且很难做到正确。想象一下,您的代码最终将使用 asterix但无论出于何种原因,something_special未安装(或由于任何其他原因导入失败,例如缺少递归依赖项)。你想尽早失败。要么在测试套件中崩溃,要么在失败的部署/回滚中。你不想要的是 ImportError运行时崩溃,每当应用程序碰巧最终调用 asterix (这可能意味着在凌晨 3:00 会有一些糟糕的待命人员被寻呼)。
我同意供应商代码通常很愚蠢(美化复制粘贴)。移动 asterix 的建议进入一个专用模块也不错,这实际上是我推荐的方法。

# mod_with_extra_dep.py
import something_special

def asterix():
    ...
要使依赖项可选,请使用包元数据:
# setup.py
from setuptools import setup

setup(
    ...
    extras_require={"asterix": ["something_special"]}
)
如果您使用入口点,它们还支持打包元数据中的可选要求( specsetuptools example )。这提供了两全其美:
  • 依赖关系是显式的
  • something_special除非需要,否则不会实际导入

  • 任何想要使用asterix的代码将在名称 asterix 时触发导入被访问,而不是在实际调用函数时。

    关于python - 可以在使用点而不是文件顶部导入依赖项吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64015729/

    相关文章:

    python - 对 DataFrame 中的列应用 Unique

    Python ctypes - 如何处理字符串数组

    python - 向字符串添加分钟

    python - Crontab 无法执行 python 脚本,错误为 : "[Errno 1] Operation not permitted"

    python - 是否可以控制 Celery 任务日志的 datefmt?

    python - 打开两个自己的终端,运行两个脚本并等待它们完成

    python - 如何将 numpy 数组(实际上是 BGR 图像)转换为 Base64 字符串?

    python以特定格式将三个列表合并为一个

    python - pytorch中自定义数据集的数据预处理(transform.Normalize)

    python - 将参数传递给管道中的映射器函数