如何在Python中进行相对导入?
想象一下这个文件夹结构:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
我正在编写 mod1
,需要从 mod2
导入一些东西。我该怎么做呢?
我试过 from ..sub2 import mod2
,但是出现了“在非包中尝试相对导入”的错误。
我在网上查了一下,只找到一些关于"sys.path
操作"的技巧。难道没有更简单的方法吗?
我所有的 __init__.py
文件现在都是空的。
我这样做是因为 sub2
包含了一些在子包(比如 sub1
、subX
等)之间共享的类。
我想要的行为和 PEP 366 中描述的一样(感谢 John B)。
17 个回答
- 你运行
python main.py
。 main.py
会做:import app.package_a.module_a
module_a.py
会做import app.package_b.module_b
main.py
setup.py
app/ ->
__init__.py
package_a/ ->
__init__.py
module_a.py
package_b/ ->
__init__.py
module_b.py
另外,第2步或第3步也可以用: from app.package_a import module_a
只要你的 PYTHONPATH 里有 app
,这就能正常工作。这样的话,main.py
可以放在任何地方。
所以你写了一个 setup.py
,用来把整个应用程序包和子包复制(安装)到目标系统的 Python 文件夹里,同时把 main.py
复制到目标系统的脚本文件夹里。
这是我找到的一个解决办法:
我使用相对导入的方式,比如 from ..sub2 import mod2
。然后,如果我想运行 mod1.py
,我就去 app
的上级目录,然后用 python -m app.sub1.mod1
来运行这个模块。
这个问题发生的真正原因是,相对导入是通过模块的 __name__
属性来工作的。如果模块是直接运行的,那么 __name__
就会被设置为 __main__
,这时它并不包含任何关于包结构的信息。所以,Python 就会报出 relative import in non-package
的错误。
通过使用 -m 选项,你给 Python 提供了包结构的信息,这样它就能成功解析相对导入了。
我在做相对导入时遇到过很多次这个问题。看了很多之前的回答后,我还是没能找到一个干净的解决办法,而不需要在所有文件中添加冗余的代码。(不过有些评论真的很有帮助,感谢 @ncoghlan 和 @XiongChiamiov)
希望这能帮助到正在为相对导入问题苦恼的人,因为阅读 PEP 真的不太有趣。