基于 subprocess 实现应用程序的重启并传递参数
基于 subprocess 实现应用程序的重启并传递参数
前言
在开发桌面应用程序时,有时需要实现应用程序的重启功能,并在重启过程中传递特定的参数。本学习笔记将深入探讨如何使用 Python 的 subprocess 库来实现这一功能。我们将通过 PySide6 框架构建一个示例应用程序,展示如何在不丢失当前状态的前提下,优雅地重启应用程序并传递所需参数。这一技巧对于需要动态更新配置或重新加载资源的桌面应用尤为重要。通过本文,将学会如何结合 subprocess 库与 PySide6 ,实现应用程序的灵活重启与参数传递。
1、subprocess 标准库
subprocess 库 是 Python 中用于创建和管理子进程的标准库,它提供了一个强大而灵活的接口,使得用户可以在 Python 中启动新的进程、连接它们的输入和输出,并与它们进行交互。
1.1 主要功能
- 运行外部命令:subprocess 库允许用户运行任何在命令行下可以运行的命令或程序;
- 交互式进程通信:用户可以启动一个新的进程,并通过其标准输入、输出和错误管道与之交互。例如,可以发送数据给进程的标准输入,或者读取进程的标准输出和错误输出;
- 管道和重定向:subprocess 库支持创建管道,将一个进程的输出重定向到另一个进程的输入,或者将进程的输出重定向到一个文件;
- 进程管理:用户可以监控进程的状态,等待进程结束,或者终止进程。
1.2 主要函数
1.2.1 subprocess.run()
功能:运行命令并等待其完成;
参数:包括:
参数 作用 args 要执行的命令和参数 stdin 子进程的标准输入 stdout 子进程的标准输出 stderr 子进程的标准错误 capture_output 是否捕获子进程的标准输出和标准错误 shell 是否在一个shell中执行命令 cwd 子进程的工作目录 timeout 子进程的超时时间 check 当子进程返回非零退出状态时是否引发异常 返回值:返回一个 CompletedProcess 实例,包含执行结果、返回内容等信息。
1.2.2 subprocess.Popen()
功能:创建并管理子进程,允许更细粒度地控制子进程的输入、输出和行为;
参数:与 subprocess.run() 类似,但更为详细和灵活;
方法:包括:
函数 作用 poll() 检查子进程是否已结束 communicate() 与子进程进行交互 send_signal() 向子进程发送信号 terminate() 终止子进程 kill() 强制杀死子进程
1.2.3 subprocess.check_call()
- 功能:运行命令并检查其退出状态。如果命令执行失败(即退出状态码不为0),则引发 CalledProcessError 异常。
- 参数:与 subprocess.run() 类似。
1.2.4 subprocess.check_output()
- 功能:运行命令并返回其输出。如果命令执行失败,则引发异常。
- 参数:与 subprocess.run() 类似。
2、重启逻辑
2.1 定义新的参数列表
根据需求自定义新参数列表
# 定义要传递的新参数
new_args = ['参数1', '参数2', '参数3']
2.2 当前 Python 解释器的路径
使用 sys.executable
获取当前 Python 解释器的路径
python_executable = sys.executable
2.3 获取当前脚本的绝对路径
使用 os.path.abspath(__file__)
获取当前脚本的绝对路径
script_path = os.path.abspath(__file__)
2.4 构造完整的命令行列表
构造完整的命令行列表 command,包括 Python 解释器、脚本路径和新参数
# 构造命令以重新启动应用程序(获取Python解释器及脚本文件)
python_executable = sys.executable
script_path = os.path.abspath(__file__)
command = [python_executable, script_path] + new_args
2.5 启动新的 Python 进程
使用 subprocess.Popen
启动新的 Python 进程来运行脚本并传递参数
# 重启应用程序
subprocess.Popen(command)
注意:如果程序已经打包为 .exe 文件,则需要使用 sys.executable
获取执行的 exe 文件
# 在打包后的环境中,sys.executable 将指向 .exe 文件
executable_path = sys.executable
# 构造命令来重启应用程序
command = [executable_path] + new_args
# 重启应用程序
subprocess.Popen(command)
2.6 退出当前应用程序
调用 sys.exit()
退出当前应用程序
# 退出当前应用程序
sys.exit()
3、代码示例
import sys
import os
import subprocess
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
class RestartableApp(QWidget):
def __init__(self, args=None):
super().__init__()
# 重启按键
self.restart_button = None
# 显示标签
self.arg_label = None
self.setFixedSize(300, 100)
self.initUI(args)
def initUI(self, args):
self.setWindowTitle('PySide6应用重启并传参')
self.setLayout(QVBoxLayout())
# 需要显示的参数
if args:
arg_str = ' '.join(args)
else:
arg_str = '没有参数'
self.arg_label = QPushButton(f'参数: {arg_str}')
self.arg_label.setDisabled(True)
self.layout().addWidget(self.arg_label)
self.restart_button = QPushButton('重启并传递参数')
self.restart_button.clicked.connect(self.restart_with_args)
self.layout().addWidget(self.restart_button)
@staticmethod
def restart_with_args():
# 定义要传递的新参数
new_args = ['参数1', '参数2', '参数3']
# 构造命令以重新启动应用程序(获取Python解释器及脚本文件)
python_executable = sys.executable
script_path = os.path.abspath(__file__)
command = [python_executable, script_path] + new_args
# 重启应用程序
subprocess.Popen(command)
# <editor-fold desc="如果程序已打包,则指向exe文件">
# # 在打包后的环境中,sys.executable 将指向 .exe 文件
# executable_path = sys.executable
# # 构造命令来重启应用程序
# command = [executable_path] + new_args
# # 重启应用程序
# subprocess.Popen(command)
# </editor-fold>
# 退出当前应用程序
sys.exit()
if __name__ == '__main__':
# 获取传递给入口文件的参数(不包括入口文件名称)
passed_args = sys.argv[1:]
app = QApplication(sys.argv)
window = RestartableApp(passed_args)
window.show()
sys.exit(app.exec())