python - 如何使用__init__.py修复“在非包中尝试相对导入”
我正在尝试遵循PEP 328,具有以下目录结构:
pkg/
__init__.py
components/
core.py
__init__.py
tests/
core_test.py
__init__.py
在core_test.py我有以下import语句
from ..components.core import GameLoopEvents
但是,当我运行时,我收到以下错误:
tests$ python core_test.py
Traceback (most recent call last):
File "core_test.py", line 3, in
from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package
在我周围搜索时发现“相对路径甚至无法使用__init__.py”和“从相对路径导入模块”,但它们没有帮助。
这里有什么我想念的吗?
12个解决方案
561 votes
详细阐述Ignacio Vazquez-Abrams的答案:
Python导入机制相对于当前文件的-m工作。 直接执行文件时,它没有通常的名称,而是以__package__作为其名称。 所以相对进口不起作用。
正如Igancio建议的那样,您可以使用-m选项执行它。 如果您的程序包的一部分要作为脚本运行,您还可以使用__package__属性来告诉该文件它应该在程序包层次结构中具有什么名称。
有关详细信息,请参见[http://www.python.org/dev/peps/pep-0366/]。
BrenBarn answered 2018-12-24T02:59:38Z
382 votes
是。 您没有将它用作包。
python -m pkg.tests.core_test
Ignacio Vazquez-Abrams answered 2018-12-24T02:59:04Z
195 votes
如果将当前目录附加到sys.path,则可以直接使用import components.core:
if __name__ == '__main__' and __package__ is None:
from os import sys, path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
ihm answered 2018-12-24T02:59:59Z
165 votes
这取决于您希望如何启动脚本。
如果要以经典方式从命令行启动UnitTest,即:
python tests/core_test.py
然后,因为在这种情况下'components'和'tests'是兄弟文件夹,你可以使用sys.path模块的insert或append方法导入相关模块。就像是:
import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents
否则,您可以使用'-m'参数启动脚本(请注意,在这种情况下,我们正在讨论一个包,因此您不能给出'.py'扩展名),即:
python -m pkg.tests.core_test
在这种情况下,您可以像以前一样使用相对导入:
from ..components.core import GameLoopEvents
您最终可以混合使用这两种方法,这样无论调用方式如何,您的脚本都可以正常工作。例如:
if __name__ == '__main__':
if __package__ is None:
import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents
else:
from ..components.core import GameLoopEvents
Paolo Rovelli answered 2018-12-24T03:00:41Z
14 votes
在core_test.py中,执行以下操作:
import sys
sys.path.append('../components')
from core import GameLoopEvents
Allan Mwesigwa answered 2018-12-24T03:01:01Z
9 votes
如果您的用例是用于运行测试,并且它是接缝,那么您可以执行以下操作。 而不是像nosetests那样运行测试脚本,而是使用测试框架,例如__main__.然后在命令行上输入
$$ py.test
这将在您的目录中运行测试。 这解决了由@BrenBarn指出的nosetests __main__的问题。 接下来,将一个空的__init__.py文件放入您的测试目录中,这将使测试目录成为您的包的一部分。 那你就能做到
from ..components.core import GameLoopEvents
但是,如果您将测试脚本作为主程序运行,那么事情将再次失败。 所以只需使用测试运行器。 也许这也适用于其他测试跑步者,如nosetests,但我还没有检查过。 希望这可以帮助。
deepak answered 2018-12-24T03:01:31Z
5 votes
我的快速修复是将目录添加到路径:
import sys
sys.path.insert(0, '../components/')
v4gil answered 2018-12-24T03:01:51Z
2 votes
旧线程。 我发现添加了__all__= ['submodule', ...]__init__.py文件然后在目标中使用from import *正常工作。
Laurent answered 2018-12-24T03:02:11Z
0 votes
如果有人正在寻找解决方法,我偶然发现了一个。 这是一个背景。 我想测试一下我在文件中的一种方法。 当我从内部运行它
if __name__ == "__main__":
它总是抱怨相对进口。 我尝试应用上述解决方案,但无法工作,因为有许多嵌套文件,每个都有多个导入。
这就是我做的。 我刚刚创建了一个启动器,一个外部程序,可以导入必要的方法并调用它们。 虽然不是一个好的解决方案,但它确实有效。
HappyWaters answered 2018-12-24T03:02:41Z
0 votes
试试这个
import components
from components import *
Vaishnavi Bala answered 2018-12-24T03:03:01Z
0 votes
您可以使用from pkg.components.core import GameLoopEvents,例如我使用pycharm,下面是我的项目结构图片,我只是从root包导入,然后它的工作原理:

Jayhello answered 2018-12-24T03:03:21Z
0 votes
正如Paolo所说,我们有两种调用方法:
1) python -m tests.core_test
2) python tests/core_test.py
它们之间的一个区别是sys.path [0]字符串。 由于解释将在导入时搜索sys.path,我们可以使用tests/core_test.py:
if __name__ == '__main__':
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from components import core
在此之后,我们可以使用其他方法运行core_test.py:
cd tests
python core_test.py
python -m core_test
...
注意,py36只测试过。
zhengcao answered 2018-12-24T03:03:54Z
当在Python中遇到'在非包中尝试相对导入'的错误时,问题通常在于没有正确使用__init__.py文件。解决方案包括使用python -m选项执行脚本,调整sys.path,或者在脚本中设置__package__属性。确保在需要作为包导入的目录下包含__init__.py。

4336

被折叠的 条评论
为什么被折叠?



