当 $env:path 中定义了多个可执行文件时,windows 如何决定使用哪个 python 可执行文件?

How does windows decide which python executable to use when multiple are defined in $env:path?

我有几个 python 可执行文件可从默认的 powershell 提示符中获得,如 where.exe python:

C:\Program Files\Inkscape\bin\python.exe
C:\Users1479\AppData\Local\Programs\Python\Python310\python.exe
C:\Users1479\AppData\Local\Microsoft\WindowsApps\python.exe

当我从这个 powershell 提示启动 python 解释器时,它使用第一个可执行文件:

>>>python
Python 3.9.7 (default, Sep 22 2021, 08:12:47)  [GCC 10.3.0 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', 'C:\Program Files\Inkscape\lib\python39.zip', 'C:\Program Files\Inkscape\lib\python3.9', 'C:\Program Files\Inkscape\lib\python3.9\lib-dynload', 'C:\Users\921479', 'C:\Program Files\Inkscape\lib\python3.9\site-packages']

我不想从我的 windows 路径环境变量中删除 C:\Program Files\Inkscape\bin,因为我将 inkscape 命令行工具用于其他目的。但是,我更希望 powershell 使用 python 3.10 的本地安装作为我的“默认”python 解释器。

当我检查 $env:path 变量时,Inkscape 文件夹似乎是在 python 3.10 文件夹之后定义的。所以它看起来像其他东西被用来解析 python 可执行文件:

>>>$env:path
C:\Python310\Scripts\;C:\Python310\;C:\Python39\Scripts\;C:\Python39\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\ProgramData\chocolatey\bin;C:\Users1479\AppData\Local\SumatraPDF;C:\Program Files\Git\cmd;C:\texlive21\bin\win32;C:\Program Files (x86)\PDFtk Server\bin\;C:\Program Files (x86)\Lua.1;C:\Program Files (x86)\Lua.1\clibs;C:\Program Files\Inkscape\bin;C:\Program Files\dotnet\;C:\Users1479\AppData\Local\Programs\Python\Python310\Scripts\;C:\Users1479\AppData\Local\Programs\Python\Python310\;C:\Users1479\AppData\Local\Microsoft\WindowsApps;C:\Users1479\.dotnet\tools

powershell/windows 如何决定使用哪个 python 可执行文件?我该如何修改它?

Windows 将执行什么并不重要,因为它可能取决于所使用的 API。

其中之一是CreateProcessW:

  1. The directory from which the application loaded.
  2. The current directory for the parent process.
  3. The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.
  4. The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable. Note that this function does not search the per-application path specified by the App Paths registry key. To include this per-application path in the search sequence, use the ShellExecute function.

自 Windows Vista 起,环境变量 %NoDefaultCurrentDirectoryInExePath% 配置是否应搜索当前目录(来源:MSDN)。

此外:如果您 运行 python 没有扩展名,环境变量 %PathExt% 用于查找可执行扩展名。 (来源:MSDN)。

The default value for the PATHEXT variable is: .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC

解决此类问题的好工具是 SysInternals Process Monitor。为“路径包含 python”(而不是 python.exe)设置过滤器,您将看到准确的搜索顺序。对于不包含 Python 可执行文件的目录,它将报告“没有这样的文件”。

另请注意:search order for DLLs 可能不同。

提供了很好的一般信息。

至于在 中使用 直接调用 可执行文件 仅按名称 (包括或不包括其文件扩展名) PowerShell:

  • 只在 $env:Path 中列出的目录中查找按名称指定的可执行文件,按顺序 和可执行文件使用 第一个 匹配目录。

    • 请注意,PowerShell - 与 cmd.exe 不同 - 按照设计,作为一项安全功能,不会 执行位于 current 仅按名称目录,并要求您通过在名称前加上 .\(或使用完整路径)来明确调用此类程序的意图。

    • 换句话说:如果 python.exe 可执行文件恰好出现在 当前 目录中,提交 python:

      • cmd.exe中会执行it,
      • 而 PowerShell 会 忽略它 并仅参考 $env:PATH

与您的经验一致:即使您的 $env:Path 变量在 C:\Program Files\Inkscape\bin 之前有 C:\Python310\C:\Python39\ 的条目=],这些 包含 python.exe 可执行文件,正如您的 where.exe 命令输出所暗示的那样,这表明唯一相关的目录是 C:\Program Files\Inkscape\bin , C:\Users1479\AppData\Local\Programs\Python\Python310,以及 C:\Users1479\AppData\Local\Microsoft\WindowsApps 反映在您的 $env:Path 值中的顺序。

您在 PowerShell 中的 where.exe 调用的 等价物是(除了 PowerShell 从不在 current 中列出任何匹配项目录),使用 Get-Command cmdlet:

Get-Command python -All

省略 -All 将仅显示命令的 有效 形式,即调用时实际使用的形式。


How can I modify this?

再次从 PowerShell 视角: 根据您的需要,您有两种选择:

  • 您可以选择性地修改$env:PATH仅用于当前 PowerShell 会话,这将将修改的查找顺序限制为那个会话从它启动的进程。独立进程(例如单独的 cmd.exe 会话)不会 受到影响:

    # Simply *prepend* the desired directory to $env:Path
    $env:Path = 'C:\Users1479\AppData\Local\Programs\Python\Python310;' + $env:Path
    
  • 如果您想将修改后的查找顺序限制为仅 PowerShell 代码 - 即 pythonpython.exe 调用以 交互方式 或从 PowerShell 脚本或函数 提交 - 您可以 定义 aliases.

     New-Alias python.exe C:\Users1479\AppData\Local\Programs\Python\Python310\python.exe
     New-Alias python python.exe
    

在这两种情况下,如果您想为所有未来的 PowerShell 会话自动实施这些修改,请将语句添加到您的 $PROFILE file