Python中如何从姊妹子目录导入?

12

我看到 Stack Overflow 上有一些类似的问题,但好像没有解决我的问题或者泛用性不够。希望这个问题能够解决我的问题并且避免让我头痛。我有一个 git 仓库,它的形式如下:

repo/
   __init__.py
   sub1/
      __init__.py
      sub1a/
         __init.py
         mod1.py
   sub2/
      __init__.py
      mod2.py

我该如何在mod1.py和mod2.py之间互相导入,这取决于mod1.py或mod2.py是否为脚本(当它们各自导入时而不是被导入)?

3个回答

6
最简单的解决方案是将包含 repo 的目录放入你的 PYTHONPATH 中,然后只需使用绝对路径导入,例如 import repo.sub2.mod2 等等。
如果想要涵盖从任意目录直接作为脚本调用 python 文件的情况,则需要采用其他解决方案,最可能的方法是修改 sys.path ,以实现与设置 PYTHONPATH 相同的效果,但不需要让用户设置它。

2
我可以编辑PYTHONPATH,但是有没有一种标准的方法来强制执行它?我不希望所有新用户都必须手动更新他们的PYTHONPATH。 - Eli
1
如果您不希望用户自己管理PYTHONPATH,那么您可能需要考虑使用sys.path修改。例如,使用__file__加上os.abspath查找脚本所在的位置,然后获取正确级别的目录作为repo的父目录,最后将其插入到sys.path中。 - Amber

3

如果您使用 Python 2.6+,您有两个选择:

  • 相对导入
  • repo 添加到您的 PYTHONPATH

使用相对导入时,会使用一个特殊的点语法:

在包 sub1 中:

from .sub2.mod2 import thing

在sub1a包中:

from ..sub2.mod2 import otherthing

请注意,普通的导入语句(import module)不能与相对导入一起使用。
更好的解决方案是使用正确设置Python路径的绝对导入(示例在bash中):
export PYTHONPATH=/where/your/project/is:$PYTHONPATH

更多信息:

我真的希望这些相对导入能够工作。然而,在我的Python 2.7上,它们无法工作。 - Yair Daon
使用Python 2.7,我成功地使用了像from sub2.mod2 import thing这样的语句。 - coralvanda

0

一个脚本或模块可以导入以下两种类型的模块:

  1. 在系统路径上的模块
  2. 与导入脚本/模块属于同一包的模块。

对于模块,这些规则没有例外。 对于脚本,规则也适用,但问题在于,默认情况下运行脚本时,它不被视为包的一部分。

这意味着默认情况下,脚本只能导入在系统路径上的模块。 默认情况下,路径包括当前目录,因此如果您运行脚本,则可以导入相同目录中的模块或子目录中的包。 但仅限于此。 脚本没有“所在目录”的概念,因此它无法执行任何需要有关封闭目录的特定相对路径信息的导入。 这意味着您无法从“父目录”或“同级目录”导入内容。 只有在这些目录中的内容在系统路径上才能导入。

如果您想让脚本“知道”它在哪个包中,可以给它一个__package__属性。请参见这个之前的问题。然后,您可以在该脚本内部正常使用显式相对导入(例如from ...sub2 import mod2)。

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