在为包创建"alias"时使导入正常工作



真正的目标:我有一个在两个包(比如barbar2(之间通用的模块。我想在这两种情况下使用完全相同的测试文件,所以我想将测试导入更改为不显式命名包。(为什么?这在将模块从大型包提取到单独包的过程中很有用。(

我的想法是添加另一个模块来导入一个特定的包并为其提供"别名"。这几乎奏效了,但我遇到了一个问题。

最初我有:

# test.py:
from bar import some_function

如果我不做任何神奇的事情,就会有两个版本的test.py:一个带有from bar import some_function,另一个带from new_bar import some_function。我希望避免这种情况,并使测试代码文件保持不变。

在我添加间接之后:

#foo.py:
import bar as baz
#test.py:
from .foo import baz  # Works!
from .foo.baz import some_function  # ModuleNotFoundError: No module named 'cur_dir.foo.baz'; 'cur_dir.foo' is not a package

我可以把foo做成一个包:

#foo/__init__.py:
import bar as baz
#test.py:
from .foo import baz  # Works!
from .foo.baz import some_function  # ModuleNotFoundError: No module named 'cur_dir.foo.baz'

错误稍微改变了一点,但仍然存在。

我知道我可以通过写来解决这个问题

# test.py:
from .foo import baz
some_function = baz.some_function

还有别的办法吗?我希望我的进口是"正常的"。

有没有一种方法可以为可以与标准导入机制一起使用的包创建"别名"?

import语句只查看实际模块及其路径,而不查看加载模块内的别名。Python的模块注册表中需要一个实际的模块别名sys.modules

import sys
import os
sys.modules["os_alias"] = os  # alias `os` to `os_alias`
import os_alias               # alias import works now
from os_alias import chdir    # even as from ... import ...

一旦将模块别名添加到sys.modules中,就可以在整个应用程序中导入。


请注意,当加载别名模块的子模块时,模块别名可能会导致细微的错误。具体来说,如果子模块没有显式别名,则会创建不同的版本。这意味着,如果版本混合,任何基于对象标识的测试(包括isinstance(original.submodule.someclass(), alias.submodule.someclass)(都将失败。

为了避免这种情况,您必须对任何别名包的所有子模块进行别名。

最新更新