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

Python 可以在使用点而不是在文件顶部导入依赖项吗?,python,Python,假设我有一个包含大量对象的模块,这些对象都不需要第三方库。几乎没有:一个函数,称为asterix(),需要第三方软件包asterix()不是本模块的重点,但在需要时可以方便地使用 仅仅为了一个功能就需要并导入整个第三方软件包,这似乎是一种耻辱。我有什么选择?正在将asterix()移动到另一个模块/包,否则看起来很愚蠢 我发现quick和clean之间的最佳平衡是在asterix()本身中进行导入,可能需要一些额外的try/except逻辑。这违反了最不出人意料的原则和进口居首的惯例。但我告诉自

假设我有一个包含大量对象的模块,这些对象都不需要第三方库。几乎没有:一个函数,称为asterix(),需要第三方软件包
asterix()
不是本模块的重点,但在需要时可以方便地使用

仅仅为了一个功能就需要并导入整个第三方软件包,这似乎是一种耻辱。我有什么选择?正在将asterix()移动到另一个模块/包,否则看起来很愚蠢

我发现quick和clean之间的最佳平衡是在
asterix()
本身中进行导入,可能需要一些额外的try/except逻辑。这违反了最不出人意料的原则和进口居首的惯例。但我告诉自己,我会一直违反某些规定

群众智慧对此有何评论?有什么东西我遗漏了吗

def asterix(…):
尝试:
进口特别的东西
除ModuleNotFoundError作为错误外:
#对err采取措施(帮助用户解决问题!)
#特殊代码。。。

当我刚接触该语言时,我也尝试使用函数内联导入。事后来看,现在有了10多年的Python经验,我可以告诉你,这样做通常不是一个好主意。将所有导入放在模块顶部,除非您有很好的理由推迟导入内联导入隐藏依赖项。如果有很好的理由推迟导入,请确保您有必要的日志记录和监视,以了解导入失败的位置/时间

我知道这并不是一个令人满意的答案,所以我认为这是一个主要的潜在问题:Python中的打包和部署可能很复杂,而且很难正确进行。假设您的代码最终将使用asterix,但无论出于何种原因,
没有安装特殊的
(或者由于任何其他原因导入失败,例如缺少递归依赖项)。你想尽早失败。在测试套件中崩溃,或者甚至在部署/回滚失败时崩溃。当应用程序最终调用asterix时,您不希望在运行时出现
ImportError
崩溃(这可能意味着在凌晨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"]}
)
如果您使用的是入口点,它们还支持打包元数据(,)中的可选要求。这提供了两个方面的最佳效果:

  • 依赖关系是显式的
  • 除非需要,否则不会实际导入特殊的内容

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

谢谢@wim。是的,PEP8。但是,这对房间里的成年人来说更像是一个问题——当面对这种权衡时,除了书本之外还有什么诀窍?例如,“每次函数调用时进行导入检查”的缺点可以通过在成功导入时调整函数的定义来缓解。美好的但是还有另外一套折衷方案……你的解决方案是好的。每次函数调用时的导入检查只是一个快速的
dict
查找,在这里是合理的。@文件顶部的wim导入显然是PEP 8推荐的做法。但在PEP 8中也有这样一句话:“但是,要知道什么时候应该前后不一致——有时候风格指南的建议根本不适用。当有疑问时,要用你最好的判断。看看其他的例子,决定什么看起来最好。不要犹豫问!”