从终端运行脚本时发生ModuleNotFoundError

2024-04-25 05:09:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我有以下文件夹结构:

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

在fish.py中,我导入transform,如下所示:import utils.transform

当我从Pycharm运行fish.py时,它工作得非常好。然而,当我从终端运行fish.py时,我得到了错误ModuleNotFoundError: No module named 'utils'

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

我已经研究了这里建议的解决方案:Importing files from different folder,将应用程序文件夹的路径添加到sys.path帮助中。但是,我想知道是否有其他方法可以让它在不向^{中添加两行代码的情况下工作。这是因为我在/products目录中有许多脚本,不想在每个脚本中添加两行代码

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

如何让它以同样的方式为我的项目工作


Tags: path项目代码py脚本文件夹应用程序终端
2条回答

这扩展了“疯狂物理学家”的答案


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


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

python app/products/fish.py

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

If the script name refers directly to a Python file, the directory containing that file is added to the start of sys.path, and the file is executed as the __main__ module.

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

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

If this option is given, [...] the current directory will be added to the start of sys.path.

因此,您应该使用以下方法启动您的程序:

python -m app.products.fish

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


个人建议:不要将可运行脚本放入包中。仅使用包来存储所有逻辑和功能(函数、类、常量等),并编写一个单独的脚本来运行应用程序(如您所愿),将其置于包之外。这将使您免于此类问题(包括the double import trap),并且还有一个优点,即您可以为同一个包编写多个运行配置,只需为每个包编写一个单独的启动脚本

您可能想要运行python -m products.fish。它与python products/fish.py之间的区别在于前者大致相当于在shell中执行import products.fish(但是__name__设置为__main__),而后者不知道它在包层次结构中的位置

相关问题 更多 >