如何确保嵌套文件夹结构中的Python文件正确执行?
这个问题我之前折腾过好多次,核心原因其实是Python在两种运行方式下的模块搜索逻辑不一样,咱们先把差异说清楚,再给你几个靠谱的解决办法。
为什么两种运行结果不一样?
直接运行脚本的情况
当你执行python3 bar/burp/cache.py时,Python会自动把**这个脚本所在的目录(也就是bar/burp/)**加入到模块搜索路径sys.path里。而你的bar文件夹是放在foo目录下的,sys.path里根本没有foo的路径,所以Python找不到名为bar的模块,直接抛出ModuleNotFoundError。
用exec在解释器里运行的情况
你打开Python解释器时,应该是在foo目录下操作的对吧?这时候解释器的当前工作目录就是foo/,而sys.path默认会包含当前工作目录。bar文件夹正好就在foo下面,所以当你用exec执行脚本内容时,Python能顺利找到bar.pyro模块,代码自然就跑通了。
靠谱的解决办法
办法一:临时修改sys.path(适合快速测试)
在cache.py的最开头加几行代码,手动把项目根目录(foo/)加到模块搜索路径里:
import sys from pathlib import Path # 从当前脚本的路径往上找三级,就是项目根目录foo/ project_root = Path(__file__).resolve().parent.parent.parent sys.path.append(str(project_root)) from bar.pyro import explosion def setup(): print('setting things up') setup() explosion()
这种方法的好处是改完就能直接运行脚本,缺点是如果后续目录结构调整,你得跟着修改路径的层级数。
办法二:以模块方式运行(推荐的规范做法)
这是Python项目最标准的处理方式,分两步:
- 把
cache.py里的导入改成相对导入——因为cache.py属于bar.burp模块,pyro.py在它的上一级bar模块里,所以导入语句改成:
from ..pyro import explosion def setup(): print('setting things up') setup() explosion()
- 回到项目根目录
foo/,用-m参数以模块的形式运行脚本:
python3 -m bar.burp.cache
这种方式下,Python会自动把foo/加入sys.path,相对导入的逻辑也能正常工作,完全符合Python的模块设计规范。
办法三:设置PYTHONPATH环境变量(适合长期开发)
把项目根目录添加到PYTHONPATH环境变量里,这样Python不管在哪里运行,都会默认在这个路径下搜索模块:
- Linux/macOS:在终端里(确保当前在
foo目录下)执行:
export PYTHONPATH=$(pwd)
然后再运行脚本:
python3 bar/burp/cache.py
如果想让这个设置永久生效,可以把export PYTHONPATH=/绝对路径/到/foo加到你的~/.bashrc或~/.zshrc文件里。
- Windows:在命令行(同样在
foo目录下)执行:
set PYTHONPATH=%cd% python bar/burp/cache.py
这种方式不用修改任何代码,适合长期在这个项目里开发的场景。
备注:内容来源于stack exchange,提问作者Abhilash

