在Windows系统下管理多版本Python的工具实现方案
作者:薛定谔的猫喵喵
手把手打造 Python 多版本管理工具,告别 PATH 混乱,轻松切换
写在前面
作为一名开发者,我的电脑上常年安装着多个 Python 版本:2.7、3.7、3.8、3.9、3.10……每次需要切换时,要么手动修改系统环境变量 PATH,要么在项目里硬编码路径,烦不胜烦。早就羡慕 Linux 下的 nvm(Node Version Manager)和 pyenv,于是决定在 Windows 上也造一个类似的轮子。
本文记录了我从编写 PowerShell 脚本、封装成全局命令,到解决执行策略限制的完整过程。最终的效果是:在 PowerShell 中直接输入 pvm list、pvm use 3.9.10,就能像使用内置命令一样管理 Python 版本。
一、方案选择:PowerShell 函数 + 全局调用
实现一个“全局命令”通常有三种方式:
将脚本所在目录添加到 PATH 环境变量
最正统的做法,任何命令行都能识别。但需要处理管理员权限(修改系统 PATH)以及脚本执行策略。
在 PowerShell Profile 中定义函数
仅在 PowerShell 中有效,但无需修改 PATH,权限要求低。适合纯 PowerShell 用户。
编写批处理包装器 + 添加 PATH
兼容 CMD 和 PowerShell,但同样涉及 PATH 修改和提权。
考虑到我主要使用 PowerShell,且希望操作尽量简单,我选择了 方案二:在 PowerShell Profile 中定义一个函数 pvm,该函数调用我的核心脚本 pvm.ps1。这样只需要把脚本放在固定位置,然后在 profile 中写一行函数定义,即可在任何 PowerShell 窗口中使用 pvm 命令。
二、核心脚本:pvm.ps1
首先编写核心逻辑的 PowerShell 脚本。脚本的功能包括:
- 列出所有已配置的 Python 版本
- 显示当前正在使用的版本
- 切换到指定版本(修改系统
PATH,将目标版本的路径提到最前面) - 交互式菜单
完整代码如下,你只需修改 $pythonVersions 哈希表中的路径为你自己的实际安装目录即可。
# pvm.ps1 - Python Version Manager for Windows
param(
[string]$Command,
[string]$Argument
)
# 要求以管理员身份运行(因为要修改系统 PATH)
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Error "此脚本需要以管理员身份运行。请右键点击 PowerShell 并选择「以管理员身份运行」,然后重试。"
exit 1
}
# ---------- 配置区域:请根据您的实际安装路径修改 ----------
$pythonVersions = @{
"2.7.3" = @{
Path = "D:\Develop\python-2.7.3"
Scripts = "D:\Develop\python-2.7.3\Scripts"
}
"3.7.4" = @{
Path = "D:\Develop\Python37"
Scripts = "D:\Develop\Python37\Scripts"
}
"3.7.9" = @{
Path = "D:\Develop\Python-3.7.9"
Scripts = "D:\Develop\Python-3.7.9\Scripts"
}
"3.8.10" = @{
Path = "D:\Develop\python-3.8.10"
Scripts = "D:\Develop\python-3.8.10\Scripts"
}
"3.9.10" = @{
Path = "D:\Develop\python-3.9"
Scripts = "D:\Develop\python-3.9\Scripts"
}
"3.10.8" = @{
Path = "D:\Develop\python-3.10.8"
Scripts = "D:\Develop\python-3.10.8\Scripts"
}
}
# ---------------------------------------------------------
# 收集所有已知的 Python 相关路径(用于后续过滤)
$allPythonPaths = @()
foreach ($ver in $pythonVersions.Keys) {
$allPythonPaths += $pythonVersions[$ver].Path
$allPythonPaths += $pythonVersions[$ver].Scripts
}
$allPythonPaths = $allPythonPaths | Where-Object { $_ -ne '' } | ForEach-Object { [System.IO.Path]::GetFullPath($_) }
# 获取系统 PATH(机器级别)
function Get-SystemPath {
return [Environment]::GetEnvironmentVariable("Path", "Machine") -split ';' | Where-Object { $_ -ne '' }
}
# 设置系统 PATH
function Set-SystemPath($paths) {
$newPath = $paths -join ';'
[Environment]::SetEnvironmentVariable("Path", $newPath, "Machine")
$env:Path = $newPath # 立即更新当前会话
}
# 获取当前正在使用的 Python 版本(如果属于管理列表则返回版本号,否则返回 $null)
function Get-CurrentPythonVersion {
try {
$pythonExe = (Get-Command python -ErrorAction Stop).Source
} catch {
Write-Warning "当前 PATH 中未找到 python 命令。"
return $null
}
$pythonExe = [System.IO.Path]::GetFullPath($pythonExe)
foreach ($version in $pythonVersions.Keys) {
$info = $pythonVersions[$version]
$pythonDir = [System.IO.Path]::GetFullPath($info.Path)
$expectedExe = Join-Path $pythonDir "python.exe"
if ($pythonExe -eq $expectedExe) {
return $version
}
}
return $null
}
# 获取当前 Python 的完整路径(用于显示)
function Get-CurrentPythonPath {
try {
return (Get-Command python -ErrorAction Stop).Source
} catch {
return $null
}
}
# 列出所有版本,并标记当前版本
function List-Versions {
$current = Get-CurrentPythonVersion
Write-Host "已安装的 Python 版本:"
foreach ($version in ($pythonVersions.Keys | Sort-Object)) {
if ($version -eq $current) {
Write-Host "* $version (当前)" -ForegroundColor Green
} else {
Write-Host " $version"
}
}
}
# 切换到指定版本
function Use-Version($version) {
if (-not $pythonVersions.ContainsKey($version)) {
Write-Host "错误:版本 '$version' 不存在。" -ForegroundColor Red
return $false
}
$current = Get-CurrentPythonVersion
if ($current -eq $version) {
Write-Host "当前已经是 Python $version,无需切换。" -ForegroundColor Yellow
return $true
}
# 新版本需要添加的路径
$newPaths = @($pythonVersions[$version].Path, $pythonVersions[$version].Scripts) | Where-Object { $_ -ne '' }
$newPaths = $newPaths | ForEach-Object { [System.IO.Path]::GetFullPath($_) }
# 获取当前系统 PATH
$currentPath = Get-SystemPath
# 过滤掉所有已知的 Python 路径
$filteredPath = $currentPath | Where-Object {
$item = $_
try {
$fullItem = [System.IO.Path]::GetFullPath($item)
} catch {
$fullItem = $item
}
$matched = $false
foreach ($known in $allPythonPaths) {
if ($fullItem -eq $known) {
$matched = $true
break
}
}
-not $matched
}
# 构建新 PATH:新路径在前,其余在后
$newPathList = $newPaths + $filteredPath
Set-SystemPath $newPathList
Write-Host "已切换到 Python $version。请重新打开命令行窗口以使更改完全生效。" -ForegroundColor Green
return $true
}
# 主命令处理
if (-not $Command) {
# 交互模式
Write-Host "Python Version Manager (pyvm)"
while ($true) {
List-Versions
$selected = Read-Host "`n请输入要切换的版本号 (输入 q 退出)"
if ($selected -eq 'q') { exit }
$result = Use-Version $selected
if ($result) {
$continue = Read-Host "是否继续操作其他版本?(y/n)"
if ($continue -ne 'y') { exit }
}
}
} else {
switch ($Command.ToLower()) {
'list' {
List-Versions
}
'current' {
$currentVer = Get-CurrentPythonVersion
$currentPath = Get-CurrentPythonPath
if ($currentVer) {
Write-Host "当前 Python 版本: $currentVer"
} elseif ($currentPath) {
Write-Host "当前使用的 Python 不在管理列表中,路径为: $currentPath" -ForegroundColor Yellow
} else {
Write-Host "当前未检测到 Python 命令。" -ForegroundColor Red
}
}
'use' {
if (-not $Argument) {
Write-Error "请指定要使用的版本号。"
exit 1
}
$result = Use-Version $Argument
if (-not $result) { exit 1 }
}
default {
Write-Error "未知命令: $Command。可用命令: list, current, use <version>"
exit 1
}
}
}将上述代码保存为 pvm.ps1,放在一个固定路径,例如 D:\Develop\pvm\pvm.ps1。
三、将 pvm 变为全局命令:PowerShell 函数
现在我们需要在 PowerShell 的配置文件中定义一个函数 pvm,它负责调用 pvm.ps1 并传递参数。
打开 PowerShell Profile
在 PowerShell 中执行:
notepad $PROFILE
如果提示文件不存在,选择“是”创建。
添加函数定义
在打开的记事本中,输入以下内容(注意修改路径为你的 pvm.ps1 实际位置):
function pvm { & "D:\Develop\pvm\pvm.ps1" @args }保存并关闭文件。
重新加载 Profile
在 PowerShell 中执行:
. $PROFILE
四、遇到的第一道坎:执行策略限制
执行 . $PROFILE 时,你可能遇到这样的错误:
. : 无法加载文件 D:\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
这是因为 PowerShell 默认的执行策略是 Restricted,禁止运行任何脚本(包括 profile 文件)。解决办法是修改执行策略。
解决方法
以管理员身份打开 PowerShell(右键开始菜单 → Windows PowerShell (管理员))。
执行以下命令,将策略设置为 RemoteSigned:
Set-ExecutionPolicy RemoteSigned
如果只想对当前用户生效,可以加 -Scope CurrentUser:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
按提示输入 Y 确认。
现在再次加载 profile:. $PROFILE,应该就不会报错了。
解释:RemoteSigned 策略允许运行本地未签名的脚本,但会阻止从互联网下载的未签名脚本,既满足了我们运行本地脚本的需求,又兼顾了安全性。
五、使用 pvm 命令
一切就绪后,我们可以在 PowerShell 中愉快地使用 pvm 了。
列出所有版本:
pvm list
输出示例:
已安装的 Python 版本: 2.7.3 3.7.4 3.7.9 3.8.10 3.9.10 * 3.10.8 (当前)
查看当前版本:
pvm current
切换到指定版本(需要管理员权限):
pvm use 3.9.10
由于脚本需要修改系统 PATH,请确保 PowerShell 是以管理员身份运行的。如果当前不是管理员,可以右键点击 PowerShell 图标,选择“以管理员身份运行”,然后再执行 pvm use。
交互式模式:
pvm
进入交互菜单,显示版本列表并提示输入版本号切换。
六、进阶:自动提权(可选)
每次切换都要手动以管理员身份运行 PowerShell 挺麻烦的。我们可以在脚本中集成自动提权逻辑,当检测到没有管理员权限时,自动弹出 UAC 窗口以管理员身份重启脚本。
将 pvm.ps1 开头的权限检查替换为以下代码:
# 检查并自动提权
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Host "正在请求管理员权限..." -ForegroundColor Yellow
Start-Process powershell -Verb RunAs -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" $($MyInvocation.Line.Substring($MyInvocation.Line.IndexOf(' ') + 1))"
exit
}这样,当你执行 pvm use 3.9.10 且当前 PowerShell 不是管理员时,会自动弹出一个 UAC 确认窗口,确认后会在新的管理员窗口中执行切换操作。切换完成后新窗口会关闭,原窗口仍保持。
七、常见问题
1. 切换后python --version还是旧版本?
- 请确保已经重新打开了新的命令行窗口。修改系统 PATH 后,已打开的程序不会自动刷新,需要重启。
- 检查是否处于 conda 环境中,
conda deactivate后再试。
2. 修改执行策略后仍然报错?
- 确认你是在管理员 PowerShell 中修改的(如果使用
-Scope CurrentUser则无需管理员)。 - 查看当前策略:
Get-ExecutionPolicy。 - 如果策略是
Restricted,可能是修改未生效,尝试重新执行。
3. 切换时提示“找不到版本”?
- 检查
$pythonVersions中的版本号与目录是否对应,路径是否存在。 - 版本号大小写敏感,建议使用数字和点号。
八、总结
通过 PowerShell 函数 + 核心脚本的方式,我们成功在 Windows 上实现了一个轻量级的 Python 版本管理器。核心优势是:
- 独立:不依赖第三方工具,完全基于 PowerShell 和系统 API。
- 可控:代码完全开源,可根据自己的安装路径随意调整。
- 易用:
pvm list、pvm use等命令直观,与 nvm 风格一致。
如果你也在 Windows 下被多 Python 版本困扰,不妨试试这个方案。所有代码已在 Windows 10/11、PowerShell 5.1 和 7+ 上测试通过。欢迎评论区交流改进!
附:完整项目文件结构
D:\Develop\pvm\ ├── pvm.ps1 # 核心脚本 └── README.md # 说明文档(可选)
Profile 配置
# Microsoft.PowerShell_profile.ps1
function pvm {
& "D:\Develop\pvm\pvm.ps1" @args
}以上就是在Windows系统下管理多版本Python的工具实现方案的详细内容,更多关于Python多版本管理工具的资料请关注脚本之家其它相关文章!
