如何解决“在非包中尝试相对导入”,即使使用了__init__.py
我试图按照以下目录结构遵循PEP 328 :
pkg/ __init__.py components/ core.py __init__.py tests/ core_test.py __init__.py
在core_test.py
我有以下的导入语句
from ..components.core import GameLoopEvents
但是,当我运行时,我得到以下错误:
tests$ python core_test.py Traceback (most recent call last): File "core_test.py", line 3, in <module> from ..components.core import GameLoopEvents ValueError: Attempted relative import in non-package
search我发现“ 相对path不工作,即使__init__.py ”和“ 从相对path导入模块 ”,但他们没有帮助。
有什么我在这里失踪?
是。 你不是把它作为一个包装。
python -m pkg.tests.core_test
详细说明@ Ignacio的回答:
Python导入机制相对于当前文件的__name__
。 当你直接执行一个文件时,它没有通常的名字,而是以"__main__"
作为它的名字。 所以相对的import不起作用。
你可以像Iganciobuild议的那样,使用-m
选项来执行它。 如果你的软件包的一部分是作为脚本来运行的,你也可以使用__package__
属性来告诉这个文件在软件包层次结构中应该有什么名字。
有关详细信息,请参阅http://www.python.org/dev/peps/pep-0366/ 。
如果将当前目录追加到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__))))
这取决于你想如何启动你的脚本。
如果你想以经典的方式从命令行启动你的UnitTest ,那就是:
python tests/core_test.py
然后,因为在这种情况下, “组件”和“testing”是兄弟文件夹,您可以使用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
如果你的用例是用于运行testing,并且它是接缝的,那么你可以执行以下操作。 不要像python core_test.py
那样运行testing脚本,而python core_test.py
使用pytest
等testing框架。 然后在命令行中input
$$ py.test
这将运行您的目录中的testing。 这解决了__name__
指出__name__
是__main__
的问题。 接下来,将一个空的__init__.py
文件放到您的testing目录中,这将使testing目录成为您的软件包的一部分。 那你就可以做了
from ..components.core import GameLoopEvents
但是,如果将testing脚本作为主程序运行,那么事情将再次失败。 所以只需使用testing跑步者。 也许这也适用于其他testing运动员,如nosetests
testing,但我没有检查它。 希望这可以帮助。
我的快速修复是将目录添加到path:
import sys sys.path.insert(0, '../components/')
在core_test.py中,执行以下操作:
import sys sys.path.append('../components') from core import GameLoopEvents