我在使用我们拥有的大型软件存储库管理导入时遇到问题。为了清楚起见,让我们假设 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 包?”
这个问题基本上有两类解决方案:
- 帮助使丢失的包在用户的机器上可用。
- 您可以将代码分发为 package用户可以使用
pip
安装。只需包括 dependency specifications在您的分发包中,pip
将让用户自动下载和安装任何缺少的包。 - 你可以freeze您的代码,即将您的代码转换为已经包含所有必需包的独立应用程序。
- 您可以将代码分发为 package用户可以使用
- 将您的包依赖项分为强制依赖项和可选依赖项,并调整您的代码,以使缺少可选包不会导致所有代码中断。
- 正如您已经指出的那样,您可以清理模块级导入(即
__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/