【问题标题】:Making imports work when creating "alias" for a package在为包创建“别名”时使导入工作
【发布时间】:2020-03-23 17:58:56
【问题描述】:

真正的目标:我有一个在两个包之间通用的模块(例如,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

还有其他方法吗?我希望我的进口是“正常的”。

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

【问题讨论】:

  • 请注意,模块导入(from ... 中的部分)直接在系统的模块上工作。他们不检查父模块的 content。因此,导入机器看不到 baz = bar 的别名(import bar as baz 所做的)。
  • 听起来这实际上不会帮助您实现使用相同测试文件的目标。两个包的测试文件都可以使用from bar import some_function,而不需要你的导入。随着您的导入摆弄,两个包将具有不同的别名,如果您希望您的测试文件使用别名,则必须有不同的测试文件。
  • @user2357112supportsMonica 不用摆弄我在一种情况下需要from bar1 import some_function,在另一种情况下在所有测试文件中都需要from bar2 import some_function。我只想拥有一个不同的小文件。
  • 我将 foo.baz 作为别名引入,它将在不同的 repos 中指向不同的包。

标签: python python-import importerror


【解决方案1】:

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))都将失败。

为避免这种情况,您必须为任何别名包的所有子模块设置别名。

【讨论】:

  • sys.modules 添加别名会导致一些really weird bugs。它的副作用比乍一看要多得多。
  • @user2357112supportsMonica 确实如此。所有形式的模块别名都通用的 AFAIK。
  • >"import os_alias" - from ... import ... 语法是否适用于此? // 明天试试……
  • @Ark-kun 是的,我现在已经将它添加到示例中。
猜你喜欢
  • 2020-01-07
  • 2018-01-23
  • 1970-01-01
  • 2015-10-15
  • 2018-09-26
  • 1970-01-01
  • 1970-01-01
  • 2016-09-17
  • 2019-06-22
相关资源
最近更新 更多