前置信息:shutil --- 高阶文件操作 — Python 3.12.0 文档
shutil.which (cmd, mode=os.F_OK | os.X_OK, path=None)的定义是:
返回当给定的 cmd 被调用时将要运行的可执行文件的路径。 如果没有 cmd 会被调用则返回 None
。
也就是说,运行shutil.which(“环境变量名称”)就相当于在cmd中输入了“环境变量名称”
一、问题现象①:
虚拟环境下shutil.which(“环境变量名称”)不能检测到系统环境变量下的内容,输出“None”
二、分析:
虚拟环境具有独特的环境变量,因此需要单独定义环境变量,或者继承系统环境变量
三、解决:
在“ENV/Scripts/activate.ps1”中输入【activate.ps1中是对运行环境的设置】【这段命令的作用是:以虚拟环境根目录为起点,将环境将环境变量路径添加到环境变量的Path中】:
$env:Path = "$env:VIRTUAL_ENV\环境变量路径;$env:PATH"
【注意,环境变量名必须是Path,不能是自定义的环境变量名,否则直接在在powershell终端中输入需要查找的变量文件等不会被找到(支持找到的文件包含.EXE、.BAT等等类型的文件)】
四、测试:
①在终端中输入“环境变量名称”,运行正常,有对应的信息输出。
②在终端中运行:
import shutil
print(shutil.which("环境变量名"))
运行不正常,报错说找不到这个变量。
五、问题现象②:
问题:四测试中,命名终端中都已经能够找到Path中的路径了,为什么运行shuitl.which还找不到呢?
六、分析:
cmd是应用程序,而不是系统服务,应用程序的话只要重启应用程序就可以了,而shutil.which只是检测系统服务,就需要重启系统
启发:详解Windows不重启使环境变量修改生效(经典)_不重启生效环境变量-CSDN博客
“一个程序启动时,环境变量被复制到该程序所在的环境中,在该程序执行过程中不会被除该程序以外的其他程序所改变。也就是说,假设我们启动了一个cmd程序,然后通过控制面板修改了环境变量设置,但是已经启动了的cmd所拥有的环境变量并不会被改变。如果我们在修改环境变量之后启动cmd程序,则该程序将拥有新的环境变量。
那么结论就很明显了:修改环境变量之后,如果受影响的是应用程序,那么只要简单地重新启动此应用程序,环境变量的修改就会反映到该程序中,而不必重新启动计算机;但是,如果受影响的是系统服务,就必须重新启动才能将环境变量的修改反映到系统服务中(因为没有办法在不重启计算机的情况下重新启动系统服务管理器)。”
七、解决:
重启系统
(而不是重启python程序或者重启终端。)
八、测试:
再在虚拟环境的终端中运行:
import shutil
print(shutil.which("环境变量名"))
运行正常,输出对应信息。
九、总结:
shutil.which虽然在文档中说的是调用cmd,但实际上,如果不重启的话,即便cmd已经可以响应Path中的变化,shutil.which也不能做改变,除非重启!这是因为:cmd是应用程序,而不是系统服务,应用程序的话只要重启应用程序就可以了,而shutil.which只是检测系统服务,所以必须要重启系统。
十、启发:
①及时生效的环境变量并不同于真正的系统环境变量;
②cmd也不会直接对系统环境变量及时进行操作,而像是一个“可信的代理”;
③对于shutil.which这样只是检测系统真正环境变量的程序而言并不能即时生效。