英文:
Resolve Python linting errors for dynamically loaded modules
问题
考虑以下使用嵌套模块的项目结构:
$ 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
,在 test.py
中使用 from a.c import foo
。这是因为我想在内部将代码组织在单独的子目录中,同时允许根目录中的文件使用相同的基本导入路径导入所有内容。我可以通过将以下代码添加到 a/__init__.py
来实现这一目标:
import importlib
import sys
importlib.import_module("a.b.c")
sys.modules["a.c"] = sys.modules["a.b.c"]
这样做确实有效,当我在其中的 test.py
中使用 from a.c import foo
调用 python test.py
时,我可以看到预期的 Hello world
输出。然而,各种 Python 工具和代码检查工具都不喜欢这种做法。如果我尝试在 test.py
上运行 pylint
,它会报告导入错误:
$ 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
目录中?我知道我可以在 test.py
中加入注释来禁用各种检查,比如 # pylint: disable=E0401
,但这不是可移植的(如果有人在不同的 IDE 中使用不同的代码检查工具会怎么样?),而且这只是隐藏问题而不是解决问题。我也不想将这些代码复制到根目录中的每个 .py
文件中。
或者也许这是不可能实现的,我必须始终指定正确的完整路径…?
英文:
Consider following project structure that uses nested modules:
$ tree
.
├── a
│   ├── b
│   │   ├── c
│   │   │   └── __init__.py
│   │   └── __init__.py
│   └── __init__.py
└── test.py
3 directories, 4 files
Content of test.py
file:
<!-- language: lang-python -->
from a.b.c import foo
print(foo())
Content of a/b/c/__init__.py
:
<!-- language: lang-python -->
def foo():
return "Hello world"
I'd like to omit b
when importing things and use from a.c import foo
in test.py
. This is because I want to organize the code internally in separate subdirectories while allowing files in the root directory to import everything using same base import path. I can achieve that by adding following code to the a/__init__.py
:
<!-- language: lang-python -->
import importlib
import sys
importlib.import_module("a.b.c")
sys.modules["a.c"] = sys.modules["a.b.c"]
It works and when I call python test.py
having from a.c import foo
in it I can see expected Hello world
output. However various Python tools and linters hate this. If I try to run pylint
on test.py
I can see it reporting import errors:
$ 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)
Similarly, if I try to open this in PyCharm it reports errors in the import line:
Cannot find reference 'c' in '__init__.py'
Unresolved reference 'foo'
How can I make these tools understand my intent of treating c
module as it were inside a
directory? I know I can disable various lints placing comments such as # pylint: disable=E0401
in test.py
but that's not portable (what if someone uses a different linter in some different IDE...?) and hides the problem instead of resolving it. I'd also hate to copy these into every .py
file in the root directory.
Or perhaps it's impossible to achieve and I have just always specify a proper full path...?
答案1
得分: 1
为什么不将 a
中的 __init__.py
修改为导入所有必要的子模块并使其可访问。你可以基于以下放置在 a
中的 __init__.py
来构思你的想法。
import b.c as c
然后你可以在 test.py
中这样访问模块:
import a
a.c.foo()
或者,你可以像 ivvija 建议的那样在 a
中创建一个 c.py
。
c.py:
from b.c import *
为此,你只需确保你没有在 a/b/c/__init__.py
中重新定义 __all__
,如果你这样做了,请确保添加所有所需的函数,如 __all__ = ["foo"]
。
英文:
Why don't you change __init__.py
in a
to import all the necessary submodules and make it accessible. You could base your ideas on the following __init__.py
placed in a
.
import b.c as c
Then you can access the module in test.py
as follows:
import a
a.c.foo()
Alternatively, you could create a c.py
in a
as ivvija suggests.
c.py:
from b.c import *
For this you just need to make sure you aren't redefining __all__
in a/b/c/__init__.py
and if you are make sure to add all the needed function like __all__ = ["foo"]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论