这是一个项目的原始结构:
project/
mypackage
__init__.py
moduleA.py
我想将moduleA.py
移动到子包:
project/
mypackage
__init__.py
subpackage
__init__.py
moduleA.py
我需要保持向后兼容性使用import mypackage.moduleA
的旧代码仍然可以工作。
我试着把这个添加到project/mypackage/__init__.py
:
from subpackage import moduleA
那允许我import mypackage.moduleA
。但不幸的是,它强制moduleA
在mypackage
导入后立即导入,这不是我想要的(我将moduleA
设置为可选包,因此不能保证依赖关系)。
当import mypackage
运行时,我仍然可以使用惰性模块加载启用mypackage.moduleA
导入吗?用户应该显式导入mypackage.moduleA
来触发导入。
你可以使用模块级getattr钩子来延迟加载"moduleA"第一次使用
# in mypackage/__init__.py
some_other_name = 123
def __getattr__(name):
global moduleA
if name == "moduleA":
from mypackage.subpackage import moduleA
return moduleA
raise AttributeError(name)
需要python 3.7 +。注意,getattr只会对命名空间中找不到的名字调用,所以from mypackage import some_other_name
不会调用钩子,也不会触发子包的早期导入。
from mypackage import moduleA
import mypackage
mypackage.moduleA
尽管要注意保持向后兼容性的一个重要警告。直接导入子模块将不能工作,因为该子模块实际上并不存在,无法被导入系统直接找到:
import mypackage.moduleA
为了避免破坏这种形式的import语句,您仍然可以包含mypackage/moduleA.py
文件(可以是弃用shim)
# in mypackage/moduleA.py
import warnings
warnings.warn(
message="mypackage.moduleA has moved to mypackage.subpackage.moduleA",
category=DeprecationWarning,
stacklevel=2,
)
from mypackage.subpackage.moduleA import *
弃用通知应该在几个版本中保留,然后你可以在下一个突破性的版本中完全删除mypackage/moduleA.py
,一定要在你的发行说明中提到这个变化。