【发布时间】:2020-07-29 01:32:35
【问题描述】:
以下结构(在Python 3.7 中)不允许我在模块B 中导入类A:
package:
package:
__init__.py
a:
__init__.py
a.py
b:
__init__.py
b.py
顶级__init__.py 为空白。以下是剩余的文件:
一个
# package/package/a/__init__.py
from .a import A
# package/package/a/a.py
class A:
def __init__(self):
pass
b:
# package/package/b/__init__.py
from .b import B
# package/package/b/b.py
from package.a.a import A
class B:
def __init__(self):
pass
不做任何其他事情,在 Windows 上,如果我尝试运行 b.py(在 b 文件夹中),我会收到以下错误:
ModuleNotFoundError: No module named 'package.a'
如果我在顶层添加main.py:
package:
package:
__init__.py
main.py
a:
__init__.py
a.py
b:
__init__.py
b.py
包含
# package/package/main.py
import a
import b
并运行main.py(在package/package 内),我得到了同样的错误。
如果我将b.py 更改为
# package/package/b/b.py
from ..a.a import A
class B:
def __init__(self):
pass
并运行b.py(从b 文件夹内)或main.py(从package/package 内),我得到的错误是
ValueError: attempted relative import beyond top-level package
python docs 看起来我应该能够做到这一点!
有人可以解释为什么我会收到这些错误吗?我看过几个类似的帖子,但他们没有解决我的问题:
【问题讨论】:
-
你有一个循环导入。
test.b.b导入test.a,然后导入test.a.a,然后导入test.b,后者导入test.b.b,但它正在被实例化,因此触发了ImportError,它冒泡到from test.a import A语句和因此据报道ModuleNotFoundError为test.a。具体来说,这里的导入将访问未完全加载的成员,最终导致此ImportError参见:this thread 及其链接线程以获取更多信息 -
@metatoaster 我在
a.py中删除了from test.b import B,但仍然出现同样的错误。 -
您在哪里运行
b.py?如果这只是一个随机的目录集合(即不是一个“正确的”Python 包),即使您在Test目录中,它也会失败。但是,您可以通过运行PYTHONPATH=. python test/b/b.py临时解决此问题,但这不是可移植的 - 理想情况下,您需要通过包含setup.py将您的目录结构转换为一个包,然后将其安装到您的 Python 环境中,否则导入可能根本不会工作,因为 Python 不知道如何导入它们。 -
@metatoaster 我自己在目录
b中运行b.py。我这样做是因为我仍在编写我的代码并且还没有准备好发布。出于开发目的,最佳实践是使用pipenv创建一个虚拟环境,然后将setup.py,然后pipenv install写入该虚拟环境?一般来说,是否总是需要setuptools才能使其正常工作? -
将您的项目设置为一个可以安装到不同 Python 环境中的包始终是最佳实践,这样可能更容易跨多个环境进行测试。
setuptools使这项任务变得更加容易,但并非绝对必要 - 您始终可以选择手动创建 Python 所需的元数据文件,以将项目目录视为 Python 包(例如虚拟环境中的.egg-link文件site-packages用于开发包,还有许多其他包,如PKGINFO),但不建议使用此手动过程。