想象一下这个目录结构:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
我正在编码mod1
,我需要从mod2
导入一些内容。我该怎么办?
我尝试了from ..sub2 import mod2
,但我得到了“非包裹中尝试相对导入”。
我用Google搜索,但发现只有“sys.path
操纵”黑客。有没有干净的方式?
编辑:我的所有__init__.py
目前都是空的
Edit2:我正在尝试这样做,因为sub2包含在子包(sub1
,subX
等)之间共享的类。)
Edit3:我正在寻找的行为与PEP 366中描述的行为相同(感谢John B)
答案 0 :(得分:305)
每个人似乎都想告诉你应该做什么,而不仅仅是回答这个问题。
问题是你通过将mod1.py作为参数传递给解释器来运行模块'__main__'。
来自PEP 328:
相对导入使用模块的__name__属性来确定模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它设置为'__main__'),则解析相对导入,就像模块是顶级模块一样,无论模块实际位于文件系统的哪个位置。
在Python 2.6中,他们添加了相对于主模块引用模块的功能。 PEP 366描述了这一变化。
更新:根据Nick Coghlan的说法,建议的替代方法是使用-m开关在包内运行模块。
答案 1 :(得分:115)
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
: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
来将整个app包和子包复制(安装)到目标系统的python文件夹,并main.py
来定位系统的脚本文件夹。
答案 2 :(得分:114)
以下是适合我的解决方案:
我将相对导入设为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真的不好玩。
答案 3 :(得分:46)
“Guido将包中的脚本视为反模式”(拒绝 PEP-3122)
我花了很多时间试图找到解决方案,在Stack Overflow上阅读相关帖子并对自己说“必须有更好的方法!”。看起来没有。
答案 4 :(得分:27)
这是100%解决的:
在app / main.py中导入settings / local_setting.py:
main.py:
import sys
sys.path.insert(0, "../settings")
try:
from local_settings import *
except ImportError:
print('No Import')
答案 5 :(得分:24)
def import_path(fullpath):
"""
Import a file with full path specification. Allows one to
import from anywhere, something __import__ does not do.
"""
path, filename = os.path.split(fullpath)
filename, ext = os.path.splitext(filename)
sys.path.append(path)
module = __import__(filename)
reload(module) # Might be out of date
del sys.path[-1]
return module
我正在使用此代码段从路径导入模块,希望有帮助
答案 6 :(得分:21)
nosklo's
答案
注意:所有__init__.py
个文件都是空的。
main.py
app/ ->
__init__.py
package_a/ ->
__init__.py
fun_a.py
package_b/ ->
__init__.py
fun_b.py
def print_a():
print 'This is a function in dir package_a'
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()
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
from app.package_b import fun_b
from app.package_a.fun_a import print_a
文件夹package_b
中的文件使用文件夹package_a
中的文件,这就是您想要的。右??
答案 7 :(得分:11)
不幸的是这是一个sys.path hack,但它运行得很好。
我在另一层遇到了这个问题:我已经有了一个指定名称的模块,但它是错误的模块。
我想要做的是以下(我正在使用的模块是module3):
mymodule\
__init__.py
mymodule1\
__init__.py
mymodule1_1
mymodule2\
__init__.py
mymodule2_1
import mymodule.mymodule1.mymodule1_1
请注意,我已经安装了mymodule,但在我的安装中我没有“mymodule1”
我会得到一个ImportError,因为它试图从我安装的模块中导入。
我试图做一个sys.path.append,但是没有用。什么工作是 sys.path.insert
if __name__ == '__main__':
sys.path.insert(0, '../..')
这样的黑客攻击,但一切都工作了! 所以请记住,如果您希望决定覆盖其他路径,那么您需要使用sys.path.insert(0,pathname)来使其工作!这对我来说是一个非常令人沮丧的问题,很多人都说使用“追加”功能来处理sys.path,但是如果你已经定义了一个模块(我发现它很奇怪的行为),那就行不通了。
答案 8 :(得分:10)
我想把它放在这里供我自己参考。我知道它不是很好的Python代码,但我需要一个我正在处理的项目的脚本,我想将脚本放在scripts
目录中。
import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
答案 9 :(得分:8)
正如@EvgeniSergeev在对OP的评论中所说,您可以使用以下任意位置从.py
文件导入代码:
import imp
foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()
这取自this SO answer。
答案 10 :(得分:4)
看看http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports。你可以做到
from .mod1 import stuff
答案 11 :(得分:2)
来自Python doc,
在Python 2.5中,您可以使用
from __future__ import absolute_import
指令将导入行为切换为绝对导入。这种绝对导入行为将成为未来版本(可能是Python 2.7)的默认行为。一旦绝对导入成为默认导入,import string
将始终找到标准库的版本。建议用户应尽可能多地开始使用绝对导入,因此最好在代码中开始编写from pkg import string
答案 12 :(得分:1)
我发现将“PYTHONPATH”环境变量设置为顶层文件夹更容易:
bash$ export PYTHONPATH=/PATH/TO/APP
然后:
import sub1.func1
#...more import
当然,PYTHONPATH是“全球性的”,但它并没有给我带来麻烦。
答案 13 :(得分:1)
除了John B所说的,似乎设置__package__
变量应该有所帮助,而不是改变__main__
这可能搞砸其他事情。但据我所知,它并没有完全发挥作用。
我遇到了同样的问题,PEP 328或366都没有完全解决问题,因为在一天结束时,两者都需要将包的头部包含在sys.path
中,尽我所能理解。
我还应该提一下,我没有找到如何格式化应该进入这些变量的字符串。是"package_head.subfolder.module_name"
还是什么?
答案 14 :(得分:0)
您必须将模块的路径附加到PYTHONPATH
:
export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"
答案 15 :(得分:-5)
假设您在顶层运行,然后在mod1
使用:
import sub2.mod2
而不是
from ..sub2 import mod2