考虑以下使用嵌套模块的项目结构:
$ tree
.
├── a
│ ├── b
│ │ ├── c
│ │ │ └── __init__.py
│ │ └── __init__.py
│ └── __init__.py
└── test.py
3 directories, 4 files
test.py
文件的内容:
from a.b.c import foo
print(foo())
a/b/c/__init__.py
的内容:
def foo():
return "Hello world"
我想在导入东西时省略
b
并在from a.c import foo
中使用test.py
。这是因为我想在内部将代码组织在单独的子目录中,同时允许根目录中的文件使用相同的基本导入路径导入所有内容。我可以通过在a/__init__.py
中添加以下代码来实现:
import importlib
import sys
importlib.import_module("a.b.c")
sys.modules["a.c"] = sys.modules["a.b.c"]
它有效,当我调用
python test.py
时,其中包含 from a.c import foo
我可以看到预期的 Hello world
输出。然而,各种 Python 工具和 linters 讨厌这个。如果我尝试在 pylint
上运行 test.py
,我可以看到它报告导入错误:
$ pylint test.py
************* Module test
test.py:1:0: C0114: Missing module docstring (missing-module-docstring)
test.py:1:0: E0401: Unable to import 'a.c' (import-error)
test.py:1:0: E0611: No name 'c' in module 'a' (no-name-in-module)
------------------------------------------------------------------
Your code has been rated at 0.00/10 (previous run: 0.00/10, +0.00)
同样,如果我尝试在 PyCharm 中打开它,它会在导入行中报告错误:
Cannot find reference 'c' in '__init__.py'
Unresolved reference 'foo'
我怎样才能让这些工具理解我处理
c
模块的意图,就像它在a
目录中一样?我知道我可以禁用各种 lint 放置评论,例如 # pylint: disable=E0401
在 test.py
但这不是可移植的(如果有人在一些不同的 IDE 中使用不同的 linter 怎么办......?)并隐藏问题而不是解决它。我也不想将这些复制到根目录中的每个.py
文件中。
或者也许这是不可能实现的,我总是指定一个正确的完整路径......?
为什么不更改
__init__.py
中的a
以导入所有必要的子模块并使其可访问。您可以根据以下__init__.py
放置在a
.中的想法
import b.c as c
然后就可以访问
test.py
中的模块,如下:
import a
a.c.foo()
或者,您可以按照 ivvija 的建议在
c.py
中创建一个a
。
c.py:
from b.c import *
为此,您只需要确保您没有在
__all__
中重新定义 a/b/c/__init__.py
并且如果您确保添加所有需要的功能,例如 __all__ = ["foo"]