我写了一个包P。在P的根有一个模块m0。P 内部的某处有模块 m1,m2,... 需要从 m0 导入
当然,我可以在每个模块中编写:
from P.m0 import ...
但是,如果我更改 PI 的名称,则必须重新访问所有地方并重写此类语句。
我也可以使用相对导入,但如果我在包层次结构中移动一个不同级别的模块,我必须修复点数。
还有其他一些原因,但归根结底,我真的想说从位于我的包根目录的模块 m0 导入,最好的表达方式是什么?
我写了一个包P。在P的根有一个模块m0。P 内部的某处有模块 m1,m2,... 需要从 m0 导入
当然,我可以在每个模块中编写:
from P.m0 import ...
但是,如果我更改 PI 的名称,则必须重新访问所有地方并重写此类语句。
我也可以使用相对导入,但如果我在包层次结构中移动一个不同级别的模块,我必须修复点数。
还有其他一些原因,但归根结底,我真的想说从位于我的包根目录的模块 m0 导入,最好的表达方式是什么?
那是不可能的。
但是,如果您执行重大重构,在子包之间移动模块,则必须更新一些相对导入不是一个大问题。
如果您不使用相对导入,同样适用于重命名顶级包名称 - 甚至可以通过搜索和替换所有文件来快速完成。
如果你愿意稍微修改你的问题,你可以摆脱这个。
如果您的包的唯一入口点受到控制;例如,您只能通过执行类似调用之类的操作来测试您的testsuite package/.../module.py
代码
那么你可以确保你做的第一件事是import firstthing
,并且在 package/firstthing.py 你有:
import sys
import os.path
packageDir = os.path.split(__name__)[0]
sys.path[:] = sys.path+[packageDir] # or maybe you want it first...
主要的警告是,如果不通过入口点,您将无法运行 python 文件。我总是想为我用 python 编写的每个项目执行此操作(以使相对导入工作得很好),但我个人觉得这太不方便了,我就放弃了。
还有第二种选择。指定你的包需要 python 路径中的另一个包并不是不合理的。这个包可能是一个执行重大黑客攻击的实用程序包。例如,如果包的名称是“x”,您可以import x
使用检查模块在解释器堆栈上执行反射,让您确定从哪个模块导入它。然后,您可以通过向上父目录执行某种“向后 os.walk”,直到找到包的根目录(通过检查一些特殊的指示文件、清单或其他东西)。然后代码将以编程方式执行上述python路径的修改sys.path
. 它与上面的相同,但是您可以自由地执行诸如运行任何 python 文件之类的操作,而无需通过一个糟糕的入口点。
如果你对 shell 环境有极端的控制,你也可以增加 $PYTHONPATH 以包含你的包目录,但这在很多方面都非常脆弱,而且相当不雅。