从终端运行脚本时出现ModuleNotFoundError

ser*_*eva 8 python pycharm python-3.x

我具有以下文件夹结构:

  • app
    • __init__.py
    • utils
      • __init__.py
      • transform.py
    • products
      • __init__.py
      • fish.py

在fish.py中,我transform按以下方式导入:import utils.transform

当我从Pycharm运行fish.py时,它运行得很好。但是,当我从终端运行fish.py时,出现了error ModuleNotFoundError: No module named 'utils'

我在终端中使用的命令:来自app文件夹python products/fish.py

我已经研究了这里建议的解决方案:从不同的文件夹导入文件,将应用程序文件夹的路径添加到sys.path帮助中。但是我想知道是否还有其他方法可以使它工作而无需向中添加两行代码fish.py。这是因为我在/ products目录中有很多脚本,并且不想在其中每个脚本中添加两行代码。

我研究了一些开源项目,并且看到了很多示例,这些示例是从并行文件夹中导入模块而不向sys.path中添加任何内容的,例如:https : //github.com/jakubroztocil/httpie/blob/master/httpie/plugins /builtin.py#L5

如何以相同的方式使其适用于我的项目?

Ana*_*and 23

这扩展了@Mad Physicist 的答案。


首先,假设app本身是一个包(因为您添加__init__.py了它)并且utilsproducts它的子包,您应该将导入更改为import app.utils.transform,并从根目录( 的父目录app)运行Python。这个答案的其余部分假设你已经做到了这一点。(如果您无意制作app根包,请在评论中告诉我。)


问题是您app.products.fish像脚本一样运行,即通过将文件的完整路径提供给命令python

python app/products/fish.py
Run Code Online (Sandbox Code Playgroud)

这使得 Python 认为该fish.py文件是一个独立的脚本,不属于任何包的一部分。正如文档中所定义的(请参阅此处,在 下<script>),这意味着 Python 将在与脚本相同的目录中搜索模块,即app/products/

如果脚本名称直接引用 Python 文件,则包含该文件的目录将添加到 的开头sys.path,并且该文件作为__main__模块执行。

但当然,该app文件夹不在 中,因此如果您尝试导入或任何子包(例如) app/products/,它会抛出错误。appapp.utils

启动属于包一部分的脚本的正确方法是使用-m(module) 开关( reference ),它将模块路径作为参数并将该模块作为脚本执行(但将当前工作目录保留为模块)搜索路径):

如果给出此选项,[...]当前目录将被添加到sys.path.

因此,您应该使用以下命令来启动您的程序:

python -m app.products.fish
Run Code Online (Sandbox Code Playgroud)

现在,当app.products.fish尝试导入模块时,它将在当前工作目录(包含树)中app.utils.transform搜索并成功。appapp/...


作为个人建议:不要将可运行的脚本放入 packages 中。仅使用包来存储所有逻辑和功能(函数、类、常量等),并编写单独的脚本来根据需要运行应用程序,并将其放在包之外。这将使您避免此类问题(包括双重导入陷阱),并且还有一个优点是您可以为同一个包编写多个运行配置,只需为每个包创建一个单独的启动脚本即可。


Mad*_*ist 7

您可能想跑步python -m products.fish。和之间的区别python products/fish.py是,前者大致等同import products.fish于在shell中进行操作(但__name__设置为__main__),而后者不了解其在包层次结构中的位置。

  • 谢谢 Mad,我刚刚尝试运行“python -m products.fish”,它有效! (2认同)