为何Python脚本单独运行时能找到win32api模块,作为子进程从另一个脚本调用时却找不到?
为何Python脚本单独运行时能找到win32api模块,作为子进程从另一个脚本调用时却找不到?
这问题我之前踩过一模一样的坑!核心原因就是子进程调用的Python解释器和你单独运行时的不是同一个环境,具体细节和解决办法给你理得明明白白:
问题根源拆解
你单独运行脚本时,命令行前缀显示(.venv),说明你已经激活了项目的虚拟环境,此时用py -m ...调用的是虚拟环境.venv里的Python解释器——这个环境里你肯定已经安装了pywin32包(win32api是它的核心子模块),所以导入完全正常。
但你用subprocess.run(["python", ...])调用时,这里的python命令默认指向的是系统全局的Python解释器(或者未激活虚拟环境时的默认Python),而这个环境里根本没装pywin32依赖,自然就抛出ModuleNotFoundError了。
解决办法(按推荐优先级排序)
1. 直接调用虚拟环境内的Python解释器(最稳妥)
指定子进程用虚拟环境里的Python路径,Windows下虚拟环境的Python一般在.venv/Scripts/python.exe。如果你的GUI脚本本身也是在虚拟环境中运行的,用sys.executable获取当前解释器路径会更灵活,不用硬编码:
import tkinter as tk from tkinter import ttk, scrolledtext import subprocess import sys # 新增导入 root = tk.Tk() root.title("Test WinAPI") def build_sel(): # 用父进程同环境的Python解释器调用子脚本 subprocess.run([sys.executable, "list_discs_with_folders.py", "dlist.txt"]) # 也可以直接写死虚拟环境路径(适合GUI脚本在全局环境运行的情况): # subprocess.run([r".venv/Scripts/python.exe", "list_discs_with_folders.py", "dlist.txt"]) btn_run = ttk.Button(root, text="Build selected", command=build_sel) btn_run.pack() root.mainloop()
这种方式能100%保证子进程和你单独运行时用的是同一个Python环境,依赖完全一致。
2. 让子进程先激活虚拟环境再执行脚本(繁琐但可选)
Windows下可以通过调用虚拟环境的激活批处理脚本,再执行目标脚本,但需要开启shell=True支持命令串联,兼容性稍差:
def build_sel(): subprocess.run( [r".venv/Scripts/activate.bat", "&&", "python", "list_discs_with_folders.py", "dlist.txt"], shell=True )
验证小技巧
你可以在命令行分别执行where python:
- 激活虚拟环境前:显示的是系统全局Python路径
- 激活虚拟环境后:会优先显示
.venv/Scripts/python.exe
对比这两个结果,就能直观看到环境差异带来的路径不同。
备注:内容来源于stack exchange,提问作者Titus




