如何将模块从根移到子包中以保持向后兼容性



这是一个项目的原始结构:

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。但不幸的是,它强制moduleAmypackage导入后立即导入,这不是我想要的(我将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,一定要在你的发行说明中提到这个变化。

相关内容

  • 没有找到相关文章

最新更新