我有以下文件夹结构:
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'
。
我在终端中使用的命令:来自app文件夹python products/fish.py
。
我已经查看了此处建议的解决方案:Importing files from different folder,将应用程序文件夹的路径添加到sys.path
帮助中。但是我想知道是否有任何其他方法使其工作而不在fish.py
中添加两行代码。这是因为我在/ products目录中有很多脚本,并且不想在每个脚本中添加2行代码。
我查看了一些开源项目,我看到很多从并行文件夹导入模块的示例,而没有在sys.path中添加任何内容,例如这里: https://github.com/jakubroztocil/httpie/blob/master/httpie/plugins/builtin.py#L5
如何以同样的方式使它适用于我的项目?
答案 0 :(得分:6)
您可能想要运行python -m products.fish
。它与python products/fish.py
之间的区别在于前者大致相当于在shell中执行import products.fish
(但__name__
设置为__main__
),而后者没有意识到它在包层次结构中的位置。
答案 1 :(得分:3)
这是@Mad Physicist的回答。
首先,假设app
本身是一个程序包(因为您已经向其中添加了__init__.py
),并且utils
和products
是其子程序包,则应更改导入import app.utils.transform
,然后从根目录(app
的父级)运行Python。该答案的其余部分假定您已完成此操作。 (如果您不是打算将app
用作根软件包,请在评论中告诉我。)
问题是您正在运行app.products.fish
,就好像它是一个脚本一样,即,通过将文件的完整路径提供给python
命令:
python app/products/fish.py
这使Python认为此fish.py
文件是独立脚本,不属于任何软件包。根据文档中的定义(请参见<script>
下的here),这意味着Python将在与脚本相同的目录中搜索模块,即app/products/
:
如果脚本名称直接指向Python文件,则目录 包含该文件的文件将添加到
sys.path
的开头,并且该文件 作为__main__
模块执行。
但是,当然app
文件夹不在app/products/
中,因此如果您尝试导入app
或任何子包(例如app.utils
),它将引发错误。
启动作为软件包一部分的脚本的正确方法是使用 -m
(模块)开关(reference),它将模块路径作为一个参数并将其作为脚本执行(但将当前工作目录保留为模块搜索路径):
如果给出此选项,则当前目录[...] 将会添加到
sys.path
的开头。
因此,您应该使用以下代码启动程序:
python -m app.products.fish
现在,当app.products.fish
尝试导入app.utils.transform
模块时,它将在您当前的工作目录(包含app
树)中搜索app/...
并成功。 / p>
作为个人建议:请勿将可运行的脚本放入包中。仅使用包来存储所有逻辑和功能(函数,类,常量等),并编写一个单独的脚本以根据需要运行您的应用程序,并将其放在包的外部。这样可以避免出现此类问题(包括the double import trap),并具有一个优点,即您可以为每个程序包编写单独的启动脚本,从而为同一程序包编写多个运行配置。