如何在Python中进行相对导入?
想象一下这个目录结构:如何在Python中进行相对导入?,python,python-import,python-module,Python,Python Import,Python Module,想象一下这个目录结构: app/ __init__.py sub1/ __init__.py mod1.py sub2/ __init__.py mod2.py 我正在编码mod1,我需要从mod2导入一些东西。我该怎么做 我尝试了从..sub2 import mod2导入,但得到了一个“在非包中尝试相对导入” 我搜索了一下,但只找到了“sys.pathmanipulation”黑客。难道没有干净的方法吗 编辑:我的所有\uu
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
我正在编码mod1
,我需要从mod2
导入一些东西。我该怎么做
我尝试了从..sub2 import mod2导入,但得到了一个“在非包中尝试相对导入”
我搜索了一下,但只找到了“sys.path
manipulation”黑客。难道没有干净的方法吗
编辑:我的所有\uuuuu init\uuuuuuy.py
当前为空
Edit2:我之所以这么做是因为sub2包含跨子包共享的类(sub1
,subX
,等等)
Edit3:我所寻找的行为与(感谢John B)中描述的行为相同,每个人似乎都想告诉你应该做什么,而不仅仅是回答问题
问题是,通过将mod1.py作为参数传递给解释器,您正在以“\uuuu main\uuuu”的形式运行模块
发件人:
相对导入使用模块的_name __属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,将其设置为“\uuuu main\uuuuu”),则将解析相对导入,就像模块是顶级模块一样,而不管模块在文件系统上的实际位置如何
在Python2.6中,他们添加了相对于主模块引用模块的功能。描述更改
更新:根据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
does:import app.package\u a.module\u a
module_a.py
doesimport app.package_b.module_b
或者2或3可以使用:从app.package\u导入模块\u a
只要PYTHONPATH中有应用程序
,这就行了main.py
可以在任何地方
因此,您需要编写一个setup.py
来将整个应用程序包和子包复制(安装)到目标系统的python文件夹中,并将main.py
复制到目标系统的脚本文件夹中
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
我用这个片段从路径导入模块,希望对
在Python2.5中,可以使用from\uuuuuu future\uuuuuu import absolute\u import
指令将导入的行为切换为绝对导入。这种绝对导入行为将成为未来版本(可能是Python 2.7)的默认行为。一旦默认为绝对导入,导入字符串
将始终找到标准库的版本。建议用户尽可能多地使用绝对导入,因此最好在代码中开始从pkg导入字符串编写
看一看。你可以
from .mod1 import stuff
“Guido将包内运行的脚本视为反模式”(已拒绝)
)
我花了很多时间试图找到一个解决方案,阅读了这里有关堆栈溢出的相关文章,并对自己说:“一定有更好的方法!”。看起来没有。不幸的是,这是一个sys.path hack,但它运行得很好
我在另一层遇到了这个问题:我已经有一个指定名称的模块,但它是错误的模块
我想做的是以下几点(我工作的模块是模块3):
请注意,我已经安装了mymodule,但在我的安装中没有“mymodule1”
我会得到一个ImportError,因为它试图从我安装的模块导入
我尝试执行sys.path.append,但没有成功。工作的是一个系统路径.insert
if __name__ == '__main__':
sys.path.insert(0, '../..')
有点像黑客,但都成功了!
因此,请记住,如果您希望您的决定覆盖其他路径,那么您需要使用sys.path.insert(0,pathname)使其生效!这对我来说是一个非常令人沮丧的症结所在,很多人都说要在sys.path中使用“append”函数,但如果已经定义了一个模块(我发现它的行为非常奇怪)我发现将“PYTHONPATH”环境变量设置到顶部文件夹更容易:
bash$ export PYTHONPATH=/PATH/TO/APP
然后:
当然,PYTHONPATH是“全局的”,但它还没有给我带来麻烦。除了John B所说的之外,设置\uuuu package\uuuuu
变量应该会有所帮助,而不是更改\uu main\uuuuu
,这可能会搞糟其他事情。但就我所能测试的而言,它并没有完全按照它应该的方式工作
我有同样的问题,PEP 328或366都不能完全解决问题,因为据我所知,在一天结束时,两者都需要将包头包含在sys.path
中
我还应该提到,我没有找到如何格式化应该进入这些变量的字符串。是“包头.子文件夹.模块名”
还是什么 让我把这个放在这里作为我自己的参考。我知道这不是一个好的Python代码,但是我需要一个脚本用于我正在进行的项目,我想把脚本放在scripts
目录中
import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
以下是适合我的解决方案:
我以from..sub2 import mod2
然后,如果我想运行mod1.py
,那么我将转到app
的父目录,并使用python-m开关作为python-m app.sub1.mod1
运行模块
相对导入出现此问题的真正原因是,相对导入通过使用模块的\uuu name\uuu
属性来工作。如果模块正在直接运行,则\uuuu name\uuuu
设置为\uuuu main\uuuu
,并且它不包含任何有关包结构的信息。这就是python抱怨非包中的相对导入错误的原因
因此,通过使用-m开关,您可以提供包
import sub1.func1
#...more import
import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
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()
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
import imp
foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()
import sys
sys.path.insert(0, "../settings")
try:
from local_settings import *
except ImportError:
print('No Import')
export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"