前言
我正在开发一个项目,该项目实际上是可以通过pip安装的Python程序包,但它也提供了命令行界面。 使用python mypackage/main.py安装项目后,我的项目运行没有问题,但是,在更改了其中一个项目文件中的内容后,每次由谁来执行此操作? 我需要通过简单的python -m mypackage.main运行整个过程。
/my-project
- README.md
- setup.py
/mypackage
- __init__.py
- main.py
- common.py
相同问题的不同面孔
我尝试从python -m mypackage.main模块中导入python mypackage/main.py中的一些功能。 我尝试了不同的配置,这些配置会产生不同的错误,并且我想与大家分享我的观察结果,并为将来我留下快速笔记。
相对进口
我首先尝试的是相对导入:
from .common import my_func
我使用以下简单的代码运行应用程序:python mypackage/main.py。不幸的是,这产生了以下错误:
ModuleNotFoundError: No module named '__main__.common'; '__main__' is not a package
导致此问题的原因是python mypackage/main.py是直接由python -m mypackage.main命令执行的,因此成为名为common的主模块。如果将此信息与我们使用的相对导入连接,则会得到错误消息__main__.common中的内容。这是 在Python文档中进行了解释:
请注意,相对导入基于当前模块的名称。 由于主模块的名称始终为python mypackage/main.py,因此打算用作Python应用程序主模块的模块必须始终使用绝对导入。
当我用python mypackage/main.py安装程序包并运行它时,它工作得很好。 我还能够在Python控制台中导入python -m mypackage.main模块。 因此,看起来只有直接运行它才有问题。
绝对进口
让我们遵循文档中的建议,并将import语句更改为其他内容:
from common import my_func
如果我们现在尝试像以前那样运行它:python mypackage/main.py,则它将按预期工作! 但是,当您像我一样在使用pip安装它之后开发需要作为独立命令行工具工作的东西时,有一点需要注意。 我安装了python -m mypackage.main的软件包,然后尝试运行它。
ModuleNotFoundError: No module named 'common'
更糟糕的是,当我打开Python控制台并尝试手动导入python mypackage/main.py模块(python -m mypackage.main)时,出现了与上述相同的错误。 原因很简单:common不再是相对导入,因此Python尝试在已安装的软件包中找到它。 我们没有这样的软件包,这就是为什么它失败了。
仅当创建使用python mypackage/main.py命令执行的典型Python应用程序时,使用绝对导入的解决方案才能很好地工作。
使用包名称导入
还有第三种可能性可以导入python mypackage/main.py模块:
from mypackage.common import my_func
只要我们从python mypackage/main.py的上下文中进行操作,这与相对导入方法并没有太大区别。同样,尝试使用python -m mypackage.main运行此操作的结束类似:
ModuleNotFoundError: No module named 'mypackage'
解释器很正确,您没有安装这样的软件包,这可能会很令人讨厌。
解决方案
对于简单的Python应用程序
只需使用绝对导入(不带点),一切都会好起来的。
对于开发中的可安装Python应用程序
使用相对导入,或使用开头带有软件包名称的导入,因为在安装应用程序时需要使用此类导入。 在开发中运行此类模块时,可以使用python mypackage/main.py选项执行Python:
-m mod : run library module as a script (terminates option list)
因此,不要像python mypackage/main.py那样做:python -m mypackage.main。