想象一下这个目录结构:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
我正在编写mod1,我需要从mod2中导入一些东西。我该怎么做呢?
我试过…sub2导入mod2,但我得到了一个“尝试相对导入非包”。
我搜索了一下,但只找到了“sys”。路径操纵“黑客”。没有干净的方法吗?
编辑:我所有的__init__.py目前是空的
Edit2:我试图这样做是因为sub2包含跨子包共享的类(sub1、subX等)。
Edit3:我正在寻找的行为与PEP 366中描述的相同(感谢John B)
每个人似乎都想告诉你应该做什么,而不仅仅是回答问题。
问题是,通过将mod1.py作为参数传递给解释器,您正在以'__main__'的身份运行模块。
PEP 328:
相对导入使用模块的__name__属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它被设置为'__main__'),则相对导入将被解析,就像该模块是顶级模块一样,而不管该模块实际位于文件系统的哪个位置。
在Python 2.6中,他们添加了相对于主模块引用模块的功能。PEP 366描述了这个变化。
更新:根据Nick Coghlan的说法,推荐的替代方案是使用-m开关在包中运行模块。
main.py
setup.py
app/ ->
__init__.py
package_a/ ->
__init__.py
module_a.py
package_b/ ->
__init__.py
module_b.py
运行python main.py。
Main.py执行如下操作:导入app.package_a.module_a
Module_a.py会导入app.package_b.module_b
或者2或3可以使用:from app.package_a import module_a
只要你的PYTHONPATH中有app,这就可以工作。Main.py可以在任何地方。
所以你写了一个setup.py来复制(安装)整个应用程序包和子包到目标系统的python文件夹,main.py到目标系统的脚本文件夹。
很不幸,这是一个系统。路径hack,但它工作得很好。
我在另一个层遇到了这个问题:我已经有一个指定名称的模块,但它是错误的模块。
我想做的是以下(我从模块是模块3):
mymodule\
__init__.py
mymodule1\
__init__.py
mymodule1_1
mymodule2\
__init__.py
mymodule2_1
import mymodule.mymodule1.mymodule1_1
注意,我已经安装了我的模块,但在我的安装中,我没有“mymodule1”
我会得到一个ImportError,因为它试图从我安装的模块中导入。
我尝试了一个sys。path。追加,这行不通。sys.path.insert起作用了吗
if __name__ == '__main__':
sys.path.insert(0, '../..')
有点像黑客,但都能用上了!
所以请记住,如果你想要你的决定覆盖其他路径,那么你需要使用sys.path。插入(0,pathname)让它工作!这对我来说是一个非常令人沮丧的症结,很多人说要使用“追加”功能到sys。路径,但如果你已经定义了一个模块,这就行不通了(我发现这是非常奇怪的行为)
下面是一个适合我的解决方案:
我做相对进口从..Sub2导入mod2
然后,如果我想运行mod1.py,然后我进入app的父目录,使用python -m开关运行模块,如python -m app.sub1.mod1。
相对导入出现此问题的真正原因是相对导入通过接受模块的__name__属性来工作。如果模块是直接运行的,那么__name__将被设置为__main__,并且它不包含任何关于包结构的信息。而且,这就是python抱怨在非包错误中相对导入的原因。
因此,通过使用-m开关,您可以向python提供包结构信息,通过这些信息,python可以成功地解析相对导入。
在进行相对导入时,我多次遇到过这个问题。而且,在阅读了之前所有的答案后,我仍然无法弄清楚如何以一种干净的方式解决它,而不需要在所有文件中放入样板代码。(尽管有些评论真的很有帮助,感谢@ncoghlan和@XiongChiamiov)
希望这能帮助那些与相对进口问题作斗争的人,因为通过PEP真的不好玩。
用例子解释nosklo的答案
注意:所有__init__.py文件都是空的。
main.py
app/ ->
__init__.py
package_a/ ->
__init__.py
fun_a.py
package_b/ ->
__init__.py
fun_b.py
app - package_a fun_a . py
def print_a():
print 'This is a function in dir package_a'
app - package_b fun_b . py
from app.package_a.fun_a import print_a
def print_b():
print 'This is a function in dir package_b'
print 'going to call a function in dir package_a'
print '-'*30
print_a()
main.py
from app.package_b import fun_b
fun_b.print_b()
如果你运行$ python main.py,它会返回:
This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
Main.py执行如下操作
Fun_b.py从app.package_a。Fun_a import print_a
package_b文件夹中的文件使用package_a文件夹中的文件,这就是你想要的。对吧? ?