如何将模块从根移动到子包以保持向后兼容性
How to move a module from root to a subpackage maintinaing backwards compatability
这是项目的原始结构:
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
。但不幸的是,它会在导入 mypackage
后立即强制导入 moduleA
,这不是我想要的(我将 moduleA
设为可选包,因此无法保证依赖关系)。
当 import mypackage
运行时,我仍然可以启用使用惰性模块加载的 mypackage.moduleA
导入吗?用户应显式导入 mypackage.moduleA
以触发导入。
您可以使用 module level 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
为避免破坏这种形式的导入语句,您仍可以包含一个 mypackage/moduleA.py
文件(可以作为弃用垫片)
# 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
,确保 mention the change in your release notes.
这是项目的原始结构:
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
。但不幸的是,它会在导入 mypackage
后立即强制导入 moduleA
,这不是我想要的(我将 moduleA
设为可选包,因此无法保证依赖关系)。
当 import mypackage
运行时,我仍然可以启用使用惰性模块加载的 mypackage.moduleA
导入吗?用户应显式导入 mypackage.moduleA
以触发导入。
您可以使用 module level 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
为避免破坏这种形式的导入语句,您仍可以包含一个 mypackage/moduleA.py
文件(可以作为弃用垫片)
# 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
,确保 mention the change in your release notes.