在包中路径不在路径上的情况下,Python相对导入

5
我该如何将位于Python包中父目录(不在路径上)的文件导入到子目录中的文件中?(涉及编程)
我对Python包装词汇不是很清楚,以下通过示例解释:
dir1/
    __init__.py
    runner.py
    in_dir1.py
    dir2/
        __init__.py
        in_dir2.py

dir1/in_dir1.py:

def example():
    print "Hello from dir1/in_dir1.example()"

dir1/dir2/in_dir2.py

import in_dir1   #or whatever this should be to make this work
print "Inside in_dir2.py, calling in_dir1.example()"
print in_dir1.example()

假设 dir1 不在 Python 路径中,我正在寻找最佳方法将 in_dir1 导入到 in_dir2 中。

我尝试了 from .. import in_dir1from ..dir1 import in_dir1 根据这个 Q/A,但都没有起作用。 这个 Q/A 似乎包含答案; 然而,我不太确定如何解决我的问题 / 如何使用 PEP 366

两个 __init__.py 文件都是空的,我正在使用 v2.6

我正试图在不使用 Google 经常出现的任何路径 hack 的情况下完成此操作。


1
相对导入不好,嗯? - orlp
2
dir1 添加到 sys.path 并使用绝对导入。 - jfs
2个回答

3
答案在你给出的链接中:
相对导入使用一个模块的__name__属性来确定该模块在包层次结构中的位置。如果该模块的名称不包含任何包信息(例如,它被设置为“main”),则相对导入将被解析为顶级模块,而不管模块实际上位于文件系统的哪个位置。
你不能在__main__脚本中进行相对导入(例如,如果你直接运行python in_dir2.py)。
为了解决这个问题,PEP 366允许你设置全局__package__:
import dir1
if __name__ == '__main__':
    __package__ = 'dir1.dir2'
    from .. import in_dir1

请注意,包dir1仍然必须在sys.path上!您可以操纵sys.path来实现这一点。但是,那时候,相对导入有什么优势呢?

2
@Finn,这是一个边缘情况,因为您正在直接运行一个包的子模块。正确的做法是创建一个单独的脚本导入包/子模块并运行它。 - Rob Wouters
为了使其正常工作,独立的运行脚本在Python路径/目录树中的位置需要满足哪些要求? - Finn
1
@Finn: python your_script.py 会将其目录添加到 sys.path 中,因此如果您在任何地方使用绝对导入,并且 dir1your_script.py 并列,则可以导入 dir1 中的任何内容。为什么我的导入失效了? - jfs
1
Finn,就像@J.F. Sebastian所说的那样。然后你可以在包内的模块中使用相对导入。 - Rob Wouters
1
@J.F.Sebastian,不是在包内的模块。 - Rob Wouters
显示剩余2条评论

0

其实可以这样做:

import sys
sys.path.append('..')

这样做肯定是可以实现的,但请不要这么做。这样做可能会破坏其他模块。

我猜你可以在导入后直接删除它,但是也请别这么做。

编辑:

其实,这种方法也可以实现,并且我认为它是安全的:

在 in_dir2.py 中,您可以这样做:

import sys
import os
current_module = sys.modules[__name__]
indir2file=current_module.__file__
sys.path.append(os.path.dirname(os.path.abspath(indir2file))+os.sep+".."+os.sep)
import in_dir1

努力重构你的代码。


1
是的,我看到很多人在其他地方建议运行时路径黑客(实际上这是我过去使用过的方法),但每个人都会跟着sys路径黑客说“不要这样做”,所以... - Finn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接