用豆包生成一个python版本切换工具
windows电脑里安装多个版本的python,用替换环境变量的方式实现python版本的切换。
豆包生成的图标:

环境windows11,python3.13.9,pyside6
文件目录:

打包工具pyinstaller
打包命令:pyinstaller.exe --onefile --windowed --name "pvs" --icon "pythonsw128.ico" --add-data "pythonsw128.ico;." 2pypath ps6.py
程序界面:

豆包给的代码:
import sys import os import subprocess import winreg import ctypes from ctypes import wintypes from PySide6.QtGui import QIcon from PySide6.QtWidgets import ( QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QListWidget, QListWidgetItem, QPushButton, QLabel, QMessageBox, QFileDialog ) from PySide6.QtCore import Qt, QObject, QRunnable, QThreadPool, Signal, Slot def resource_path(relative_path): """获取资源的绝对路径,适用于开发环境和 PyInstaller 打包后的环境""" try: base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path) class WorkerSignals(QObject): finished = Signal() error = Signal(str) class Worker(QRunnable): def __init__(self, new_path_string): super().__init__() self.new_path_string = new_path_string self.signals = WorkerSignals() @Slot() def run(self): try: # 修改注册表中的环境变量 reg_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Environment", 0, winreg.KEY_WRITE) winreg.SetValueEx(reg_key, "PATH", 0, winreg.REG_EXPAND_SZ, self.new_path_string) winreg.CloseKey(reg_key) # 发送 WM_SETTINGCHANGE 消息,通知系统环境变量已更改 HWND_BROADCAST = 0xFFFF WM_SETTINGCHANGE = 0x001A SMTO_ABORTIFHUNG = 0x0002 # 调用 Windows API 发送消息 result = ctypes.windll.user32.SendMessageTimeoutW( HWND_BROADCAST, WM_SETTINGCHANGE, 0, ctypes.c_wchar_p("Environment"), SMTO_ABORTIFHUNG, 5000, # 等待 5 秒超时 None ) if result == 0: print("警告:发送环境变量刷新消息失败,可能需要手动重启程序才能生效。") # 触发完成信号 self.signals.finished.emit() except Exception as e: self.signals.error.emit(f"无法修改环境变量: {str(e)}") class PythonVersionSwitcher(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Python 版本管理器") self.setGeometry(100, 100, 650, 350) # 设置窗口图标 icon_path = resource_path("pythonsw128.ico") icon = QIcon(icon_path) if not icon.isNull(): self.setWindowIcon(icon) self.scan_directories = [ r"C:\Program Files", r"C:\Program Files (x86)", r"C:\Users\Administrator\AppData\Local\Programs\Python", r"C:\Python" ] self.python_versions = {} self.threadpool = QThreadPool() self.init_ui() self.scan_python_versions() def init_ui(self): central_widget = QWidget() self.setCentralWidget(central_widget) main_layout = QVBoxLayout(central_widget) top_layout = QHBoxLayout() title_label = QLabel("找到的 Python 版本:") title_label.setStyleSheet("font-size: 14px; font-weight: bold;") top_layout.addWidget(title_label) self.scan_button = QPushButton("重新扫描") self.scan_button.clicked.connect(self.scan_python_versions) top_layout.addWidget(self.scan_button) self.add_dir_button = QPushButton("添加扫描目录") self.add_dir_button.clicked.connect(self.add_scan_directory) top_layout.addWidget(self.add_dir_button) top_layout.addStretch() main_layout.addLayout(top_layout) self.version_list = QListWidget() self.version_list.setSelectionMode(QListWidget.SingleSelection) self.version_list.itemSelectionChanged.connect(self.on_selection_changed) main_layout.addWidget(self.version_list, 1) self.switch_button = QPushButton("切换到选中版本") self.switch_button.clicked.connect(self.switch_version) self.switch_button.setEnabled(False) main_layout.addWidget(self.switch_button) def on_selection_changed(self): selected_items = self.version_list.selectedItems() if not selected_items: self.switch_button.setEnabled(False) return selected_text = selected_items[0].text() if "未找到" in selected_text or "请点击" in selected_text: self.switch_button.setEnabled(False) else: self.switch_button.setEnabled(True) def add_scan_directory(self): dir_path = QFileDialog.getExistingDirectory(self, "选择 Python 安装目录的上级目录") if dir_path and dir_path not in self.scan_directories: self.scan_directories.append(dir_path) QMessageBox.information(self, "成功", f"已添加目录: {dir_path}\n将进行重新扫描。") self.scan_python_versions() elif dir_path: QMessageBox.warning(self, "提示", "该目录已在扫描列表中。") def _get_current_python_version_from_path(self): current_path = self._get_user_path() if not current_path: return None for path in current_path.split(';'): path = path.strip() if not path: continue if path.lower().endswith("scripts"): python_root = os.path.dirname(path) python_exe = os.path.join(python_root, "python.exe") if os.path.exists(python_exe): try: result = subprocess.run( [python_exe, "--version"], capture_output=True, text=True, check=True, timeout=2 ) version_output = result.stdout.strip() if version_output.startswith("Python "): return version_output[len("Python "):] except: pass return None def scan_python_versions(self): self.version_list.clear() self.python_versions.clear() self.scan_button.setEnabled(False) self.scan_button.setText("扫描中...") self.switch_button.setEnabled(False) for root_dir in self.scan_directories: if not os.path.isdir(root_dir): continue for item in os.listdir(root_dir): item_path = os.path.join(root_dir, item) if os.path.isdir(item_path): python_exe_path = os.path.join(item_path, "python.exe") if os.path.exists(python_exe_path): try: result = subprocess.run( [python_exe_path, "--version"], capture_output=True, text=True, check=True, timeout=2 ) version_output = result.stdout.strip() if version_output.startswith("Python "): version = version_output[len("Python "):] self.python_versions[version] = item_path except: pass current_version = self._get_current_python_version_from_path() if self.python_versions: for version, path in sorted(self.python_versions.items(), key=lambda x: tuple(map(int, x[0].split('.')[:2]))): item_text = f"Python {version} ({path})" if version == current_version: item_text += " **(当前)**" QListWidgetItem(item_text, self.version_list) else: QListWidgetItem("未找到任何 Python 版本。请点击'添加扫描目录'。", self.version_list) self.scan_button.setEnabled(True) self.scan_button.setText("重新扫描") def switch_version(self): selected_items = self.version_list.selectedItems() if not selected_items: return selected_text = selected_items[0].text() version_str = selected_text.split()[1] current_version = self._get_current_python_version_from_path() if version_str == current_version: QMessageBox.information(self, "提示", f"当前已处于 Python {version_str} 版本。") return if version_str not in self.python_versions: QMessageBox.warning(self, "警告", "所选版本信息无效!") return python_path = self.python_versions[version_str] scripts_path = os.path.join(python_path, "Scripts") current_path = self._get_user_path() path_list = current_path.split(';') if current_path else [] non_python_paths = [p.strip() for p in path_list if p.strip() and "python" not in p.strip().lower()] new_path_list = [scripts_path, python_path] + non_python_paths new_path_string = ';'.join(new_path_list) self.switch_button.setEnabled(False) self.switch_button.setText("处理中...") worker = Worker(new_path_string) worker.signals.finished.connect(self.on_switch_finished) worker.signals.error.connect(self.on_switch_error) self.threadpool.start(worker) def on_switch_finished(self): QMessageBox.information( self, "成功", "Python 版本切换成功!\n\n" "新的环境变量已自动刷新,重新打开命令行窗口或 IDE 即可生效。" ) self.scan_python_versions() self.switch_button.setEnabled(False) self.switch_button.setText("切换到选中版本") def on_switch_error(self, error_message): QMessageBox.critical(self, "错误", error_message) self.switch_button.setEnabled(True) self.switch_button.setText("切换到选中版本") def _get_user_path(self): try: reg_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Environment", 0, winreg.KEY_READ) path_value, _ = winreg.QueryValueEx(reg_key, "PATH") winreg.CloseKey(reg_key) return path_value except FileNotFoundError: return "" except Exception as e: QMessageBox.warning(self, "警告", f"无法读取用户 PATH: {str(e)}") return os.environ.get('PATH', '') def closeEvent(self, event): self.threadpool.waitForDone() event.accept() if __name__ == '__main__': app = QApplication(sys.argv) window = PythonVersionSwitcher() window.show() sys.exit(app.exec())

浙公网安备 33010602011771号