我正在开发一个python包K(所以它有一个__init__.py
)。
这样的包包含不同的子包,每一个关于我的工作的不同部分,让我们称之为这些M之一(所以它也有自己的__init__.py
).
现在M有2个模块A和B,每个模块包含一个或多个函数,有多少函数并不重要,但有一个区别:A中的所有函数依赖于可选的依赖性 * opt_dep_A *,并且类似地,B * opt_dep_B * 也是如此。
当安装带有pip的K时,可以安装两个可选的依赖项,例如pip install 'K[opt_dep_A]'
。
现在我希望让用户体验"模块化",这意味着如果用户对B功能感兴趣,他/她应该能够使用它们(前提是安装了opt_dep_B),而不必担心A。
问题是这样的:A和B属于同一个子包(因为它们的功能涉及同一个高级"组")。
从K或M的__init__.py
导入/显示时,如何处理此冲突?
在这两种情况下,例如从M/__init__.py
执行此操作时
from .A import func_A
from .B import func_B
如果没有安装 * opt_dep_A *,但是用户执行了from K import func_B
或from M import func_B
,那么任何捕获/未捕获的ImportError或从A模块发出的警告都会被触发,即使我从来不想从A导入东西。
不过,我还是希望A和B属于同一层:如何在保持模块化的同时,仍然保持相同的封装结构?有可能吗?
我尝试了try/except子句importlib.util.find_spec
,但问题实际上是我正在从同一级别导入一个部分。
1条答案
按热度按时间n8ghc7c11#
这里有一个基本的方法来处理这个问题。在
K/M/A.py
中,你可以有这样的代码:本质上,在函数(或类或其他)被 * 实际使用 * 之前,您不会真正导入可选依赖项。这样,您将
func_A
移到哪个名称空间都无关紧要。这就是
pandas
处理此问题的方式,请参见:https://github.com/pandas-dev/pandas/blob/8dab54d6573f7186ff0c3b6364d5e4dd635ff3e7/pandas/io/pytables.py#L559
注意,它们将导入封装在一个函数中,该函数提供一些错误处理和有用的错误消息,以及一些其他的簿记逻辑,但基本思想是相同的。
注意,处理
ImportError
* 的方法当然会 * 起作用,然后每当您尝试使用具有依赖关系的函数时,您将获得随机的NameErrors
。因此,我真的不认为这样做会节省您很多工作,因为如果您将顶层导入 Package 在try... except ImportError
中,那么您必须处理该名称将不存在于模块中的问题