如何运行从子文件夹导入的 Python 3 脚本?
Posted
技术标签:
【中文标题】如何运行从子文件夹导入的 Python 3 脚本?【英文标题】:How can I run a Python 3 script with imports from a subfolder? 【发布时间】:2018-08-12 05:55:40 【问题描述】:无论我尝试什么,自从我切换到 Python 3 我只能从项目的根文件夹运行导入脚本,但不能从子文件夹运行。我知道这里有很多关于我收到的错误消息的问题,但建议的解决方案对我不起作用。有人可以为这个小示例项目提供示例解决方案吗?我相信它会受到很多人的赞赏。
proj
├── foofolder
│ ├── __init__.py
│ └── foofile.py
├── subfolder
│ ├── __init__.py
│ └── run.py
└── __init__.py
我在foofile.py
中定义了函数foofun()
,想在run.py
中调用它。
如果run.py
直接在proj
中,它可以工作。但是(只是为了让事情井井有条)我想把它放在一个子文件夹中——这令人惊讶地似乎是不可能的。
烦人的是,我的 IDE (PyCharm) 中的自动完成功能表明 from foofolder.foofile import foofun
应该可以工作。但事实并非如此。我也无法想象任何其他导入:
from foofolder.foofile import foofun
--> ImportError: No module named 'foofolder'
from .foofolder.foofile import foofun
--> SystemError: Parent module '' not loaded, cannot perform relative import
(相同,开头有两个点。)
from proj.foofolder.foofile import foofun
--> ImportError: No module named 'proj'
即使是绝对导入也不起作用。为什么找不到proj
?
sys.path
是:['/parent/proj/subfolder', '/parent/env/lib/python35.zip', '/parent/env/lib/python3.5', '/parent/env/lib/python3.5/plat-x86_64-linux-gnu', '/parent/env/lib/python3.5/lib-dynload', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/parent/env/lib/python3.5/site-packages']
我在 virtualenv 中使用 Python 3.5.2。
编辑:当我建议这个问题特定于 Python 3 时我错了。当我在 Python 2.7.12 中检查时,问题和解决方案是相同的。
Pevogam 给出的解决方案有效。第一个直接将'..'
添加到'sys.path'
,它描述了执行run.py
的父文件夹。第二个明确添加'/parent/proj'
。
【问题讨论】:
你试过from ..foofolder
等吗?
正如我所写:开头有两个点。
【参考方案1】:
我能想到的最快的方法是:
# subfolder/run.py
import sys
sys.path.append("..")
from foofolder.foofile import foofun
foofun()
但请注意,这仅在您从其文件夹中运行 run.py 时才有效。不依赖于此的更复杂的方法是
# subfolder/run.py
import sys
import os.path as o
sys.path.append(o.abspath(o.join(o.dirname(sys.modules[__name__].__file__), "..")))
from foofolder.foofile import foofun
foofun()
您可以从任何位置到达该功能。对于所有此类模块,最简单的方法是使用指向根包的相同指针,在您的情况下,通过添加“..”来实现。然后,您可以从这个根包的角度执行任何导入。
我倾向于避免使用相对导入,因为它们会造成混淆并降低可读性,但希望这能有所帮助。
[*] 一些 IDE 可能会执行自己的项目扫描,这就是只要您在 IDE 中运行 python 代码,它们仍可能找到导入的原因。
【讨论】:
谢谢!像这样的简单解决方案是我所希望的。尽管如此,我还是很惊讶我必须做一些让人感觉有点笨拙的事情才能实现如此正常的事情。我希望以正确的方式™ 做事——只要这与我希望将相关的东西整齐地放在同一个文件夹中的愿望相交。顺便说一句,我发现在将'/parent/proj'
添加到sys.path
之后,绝对导入from proj.foofolder.foofile
仍然无法正常工作。什么会实现这一目标?
我认为总体意图是,一旦您安装了项目,就可以从标准 PYTHONPATH 中的 site-packages 文件夹访问它,因此可以从任何地方进行导入。在您开发的同时,您可以使用 IDE。将“/parent/proj”添加到sys.path
意味着您可以导入“proj”中的所有模块或包,但不能导入“proj”本身。将 '/parent' 添加到 sys.path
将允许您导入 'proj' 及其子包。【参考方案2】:
问:如何在子文件夹中运行python脚本?
A:使用PYTHONPATH=. python3 subfolder/run.py
调用
添加到 bashrc:alias pys = PYTHONPATH=. python3
。然后pys subfolder/run.py
工作!
评论:对我来说,脚本只是执行任务的东西。它永远不会从其他东西调用或导入。我有很多。
其中一些是相似的(例如taskA_reset.py
、taskB_reset.py
)。我更喜欢将其组织为taskA/reset.py
等等。但是,这样就不能再运行它们了!但是,添加路径是一个简单的解决方案,它不需要我更改任何 python 代码。
【讨论】:
【参考方案3】:我通常在 Django 项目中需要这个,并且刚刚意识到 Django 提供了一个非常方便的解决方案,它为我解决了这个问题:
$ python manage.py shell < app/utils/scripts/script.py
在script.py
中,我的导入如下:
from app.utils.functions.do_things import do_this, do_that
在这里找到:How to execute a Python script from the Django shell?
【讨论】:
以上是关于如何运行从子文件夹导入的 Python 3 脚本?的主要内容,如果未能解决你的问题,请参考以下文章
如何从子进程 python 2.7 和 Apache 读取实时输出
从子进程调用的外部 python 脚本打印 tqdm 进度条