如何创建始终有效的导入?

时间:2015-09-13 19:17:14

标签: python python-3.x

我正在努力在我的一个项目中建立一个工作结构。问题是,我有一个主包和一个像这样的结构的子包(我遗漏了所有不必要的文件):

code.py
mypackage/__init__.py
mypackage/work.py
mypackage/utils.py

utils.py有一些实用程序代码,通常只在mypackage包中使用。

我通常每个模块文件都有一些测试代码,它调用当前模块的一些方法并打印一些东西以便在一切正常工作时快速检查。此代码放在文件末尾的if __name__ == "__main__"块中。所以我直接通过import utils包含utils.py。例如,mypackage / work.py看起来像是:

import utils

def someMethod():
    pass

if __name__ == "__main__":
    print(someMethod())

但是现在我在父包中使用这个模块(例如code.py)并且我像这样导入它

import mypackage.work

我收到以下错误:

ImportError: No module named 'utils'

经过一些研究后我发现,可以通过将mypackage/文件夹添加到PYTHONPATH环境变量来解决这个问题,但这对我来说很奇怪。还有其他方法可以解决这个问题吗?我听说过相对导入,但python docs about modules

中提到了这一点
  

请注意,相对导入基于当前模块的名称。由于主模块的名称始终为" main ",用作Python应用程序主模块的模块必须始终使用绝对导入。

如何建议我如何在子模块中拥有if __name__ == "__main__"部分,并且可以在不破坏导入的情况下使用父包中的此文件?

编辑:如果我在导入工具的答案中建议使用work.py中的相对导入:

from . import utils

我收到以下错误:

SystemError: Parent module '' not loaded, cannot perform relative import

1 个答案:

答案 0 :(得分:0)

不幸的是,子模块的相对导入和直接运行不会混合。

如果要运行子模块,请将mypackage的父目录添加到PYTHONPATH或始终cd到父目录。

然后你有两种可能性:

使用绝对(from mypackage import utils)而不是相对导入(from . import utils)并像以前一样直接运行它们。该解决方案的缺点是您始终需要编写完全限定的路径,以便稍后重命名mypackage等工作。

运行python3 -m mypackage.utils等运行您的子模块,而不是运行python3 mypackage/utils.py

这可能需要一些时间来适应,但这是更正确的方式(包中的模块与独立脚本不同),您可以继续使用相对导入。

还有更多涉及__package__sys.path的“神奇”解决方案,但它们都需要在每个文件的顶部添加额外的代码,并且需要直接运行相对导入。我不推荐这些。