想象一下这个目录结构:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
我正在编码 mod1
,我需要从 mod2
导入一些东西 . 我该怎么办?
我试过 from ..sub2 import mod2
但是我得到了"Attempted relative import in non-package" .
我google了一下,但发现只有“ sys.path
操纵”黑客 . 有没有干净的方式?
编辑:我所有的 __init__.py
目前都是空的
Edit2:我正在尝试这样做,因为sub2包含跨子包共享的类( sub1
, subX
等) .
Edit3:我正在寻找的行为与PEP 366中描述的相同(感谢John B)
16 回答
每个人似乎都想告诉你你应该做什么,而不仅仅是回答这个问题 .
问题是你通过将mod1.py作为参数传递给解释器来运行模块'main' .
来自PEP 328:
在Python 2.6中,他们添加了相对于主模块引用模块的功能 . PEP 366描述了这一变化 .
Update :根据Nick Coghlan的说法,推荐的替代方法是使用-m开关在包内运行模块 .
你运行
python main.py
.main.py
:import app.package_a.module_a
module_a.py
确实import app.package_b.module_b
或者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开关作为python -m app.sub1.mod1
运行模块 .相对导入出现此问题的真正原因是相对导入通过获取模块的
__name__
属性来工作 . 如果直接运行模块,则__name__
设置为__main__
,并且它不包含有关包结构的任何信息 . 而且,这就是为什么python抱怨relative import in non-package
错误 .因此,通过使用-m开关,您可以向python提供包结构信息,通过它可以成功解析相对导入 .
在进行相对导入时,我多次遇到过这个问题 . 并且,在阅读了之前的所有答案之后,我仍然无法以干净的方式弄清楚如何解决它,而无需在所有文件中放置样板代码 . (虽然有些评论非常有用,感谢@ncoghlan和@XiongChiamiov)
希望这可以帮助那些与相对进口问题作斗争的人,因为通过PEP真的不好玩 .
"Guido views running scripts within a package as an anti-pattern"(拒绝PEP-3122)
我花了很多时间试图找到解决方案,在Stack Overflow上阅读相关帖子并对自己说“必须有更好的方法!” . 看起来没有 .
我正在使用此代码段从路径导入模块,希望有所帮助
这是100%解决的:
app /
main.py
设置/
local_setings.py
在app / main.py中导入设置/ local_setting.py:
main.py:
用例子解释
nosklo's
回答注意:所有
__init__.py
文件都是空的 .app / package_a / fun_a.py
app / package_b / fun_b.py
main.py
如果你运行
$ python main.py
它会返回:main.py:
from app.package_b import fun_b
fun_b.py确实
from app.package_a.fun_a import print_a
所以文件夹
package_b
中的文件使用了文件夹package_a
中的文件,这就是你想要的 . 对??不幸的是这是一个sys.path hack,但它运行得很好 .
我在另一层遇到了这个问题:我已经有了一个指定名称的模块,但它是错误的模块 .
我想做的是以下(我正在使用的模块是module3):
请注意,我已经安装了mymodule,但在我的安装中我没有“mymodule1”
我会得到一个ImportError,因为它试图从我安装的模块导入 .
我试图做一个sys.path.append,但是没有用 . 什么工作是 sys.path.insert
这样的黑客,但让一切工作!所以请记住,如果你想要你的决定 override other paths 那么你需要使用sys.path.insert(0,pathname)来使它工作!这对我来说是一个非常令人沮丧的问题,很多人都说_747126_函数用于sys.path,但是如果你已经定义了一个模块(我发现它很奇怪的行为),这不起作用
让我把它放在这里为我自己参考 . 我知道它不是很好的Python代码,但我需要一个脚本用于我正在处理的项目,我想将脚本放在
scripts
目录中 .正如@EvgeniSergeev在对OP的评论中所说,您可以使用以下任意位置从
.py
文件导入代码:这取自this SO answer .
看看http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports . 你可以做到
来自Python doc,
我发现将“PYTHONPATH”环境变量设置到顶部文件夹更容易:
然后:
当然,PYTHONPATH是“全球性的”,但它并没有给我带来麻烦 .
除了John B所说的,似乎设置
__package__
变量应该有所帮助,而不是改变__main__
,这可能搞砸其他事情 . 但据我测试,它并没有完全正常工作 .我有同样的问题,PEP 328或366都没有完全解决问题,因为在一天结束时,两者都需要将包的头部包含在
sys.path
中,据我所知 .我还应该提一下,我没有找到如何格式化应该进入这些变量的字符串 . 是
"package_head.subfolder.module_name"
还是什么?假设您在顶级运行,然后在
mod1
中使用:代替
我认为你要问自己的是:
为什么我需要这样做?
我的包裹分离工作做得好吗?
我不知道你为什么要这样做的背景 . 但对我来说,更清洁的设计是拥有以下包结构:
那你只需要做: