python - 构建一个大型 python 存储库,不导入所有内容

标签 python deployment import

我在使用我们拥有的大型软件存储库管理导入时遇到问题。为了清楚起见,让我们假设 repo 看起来像这样:

repo/
    __init__.py
    utils/
         __init__.py
         math.py
         readers.py             
         ...
    ...

现在我们的 __init__.py 文件已经设置好了,这样我们就可以做这样的事情了

from repo.utils import IniReader 

在这个例子中,repo/utils/__init__.py 会有

from .readers import IniReader, DatReader

从可读性的角度来看,这种结构对我们来说效果很好,但我们现在在尝试部署应用程序时遇到了问题。

问题是……假设我正在编写一个如下所示的应用:

from repo.utils import IniReader
if __name__ == '__main__':
    r = IniReader('blah.ini')
    print(r.fields)

现在 from repo.utils import IniReader 将执行 repo/utils/__init__.py,在本例中将导入 IniReader DatReader。让我们假设 DatReader 看起来像这样:

import numpy as np
import scipy
import tensorflow
from .math import transform

class DatReader():
...

它遵循 PEP8,所有的导入都在文件的顶部。

这里的问题是 DatReader 需要一些重量级的导入(例如 numpy、scipy、tensorflow 是巨大的库)。更糟糕的是,from .math import transform 可能有类似 from repo.contrib import lookup 的东西,然后它会命中 repo/contrib/__init__.py 开始链式 react 并最终导入我们的整个存储库。

对于我们所有拥有完整开发环境的开发人员来说,这真的不是问题,但现在我们正在尝试(在内部)发布应用程序,这个导入 hell 正在成为一个问题问题。

这个问题有标准的解决方案吗?我们已经讨论过将 __init__.py 保持为空,或者只是不将所有导入都放在文件顶部,如 PEP8 所述。这两种解决方案都有妥协,所以如果有人有建议或引用,我很乐意听听。

谢谢!

最佳答案

暂时后退一步,看看您似乎面临的基本问题可能会有所帮助,即:“我如何处理用户机器上丢失的 python 包?

这个问题基本上有两类解决方案:

  1. 帮助使丢失的包在用户的机器上可用。
    • 您可以将代码分发为 package用户可以使用 pip 安装。只需包括 dependency specifications在您的分发包中,pip 将让用户自动下载和安装任何缺少的包。
    • 你可以freeze您的代码,即将您的代码转换为已经包含所有必需包的独立应用程序。
  2. 将您的包依赖项分为强制依赖项和可选依赖项,并调整您的代码,以使缺少可选包不会导致所有代码中断。
    • 正如您已经指出的那样,您可以清理模块级导入(即 __init__.py 文件中的导入),这样可选包就不会“过早地”加载。在您的情况下,这意味着删除 DatReader 导入。
    • 您也已经注意到,您可以将可选的包导入移动到需要它们的类或函数中。就风格而言,这并不是真正的最佳选择,但代码本身仍然是完全有效的。每次运行函数时导入语句都会再次执行通常无关紧要,因为 actual import will still only take place once .
    • 您可以将可选包的导入包装到 try-except 子句中。这将防止发生任何导入错误(当然,一旦您尝试运行依赖于丢失包的类或函数,您仍然会遇到错误)。

try-except 子句中的导入示例:

import warnings
try:
    import scipy
except ImportError:
    warnings.warn("The python package `scipy` could not be imported. As a result "
                  "the class `repo.utils.DatReader` will not be functional.")

现在再次回到您最初的问题“这个问题有标准解决方案吗?”:我会说没有。没有一颗金子弹。所有解决方案都有自己的优点和缺点,您必须根据您的具体情况决定哪种解决方案是最佳的。

关于python - 构建一个大型 python 存储库,不导入所有内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53241381/

相关文章:

node.js - 开 Jest : Cannot import fetch

python - 在python环境中运行python脚本时检查变量?

python - pip正则表达式搜索

python - 如何显示多行而不是一行?

python - 使用多个 Python 版本 : Can IDLE be configured to see *. py3/*.py2

java - 如何修复 Tomcat 服务器中的错误内存泄漏

deployment - 运行 puppet apply 时,Puppet 不启动服务(清漆)

java - 如何在 Java 中包含上述目录中的文件?

ruby-on-rails - 我可以在同一台服务器上运行 Rails 2 和 Rails 3 应用程序吗?

ios - swift 。如何在协议(protocol)中从导入的库中声明具有返回类型的函数?