返回介绍

15.8 从 Python 启动其他程序

发布于 2024-01-22 21:44:06 字数 5201 浏览 0 评论 0 收藏 0

利用内建的subprocess模块中的Popen()函数,Python程序可以启动计算机中的其他程序(Popen()函数名中的P表示process,进程)。如果你打开了一个应用程序的多个实例,每个实例都是同一个程序的不同进程。例如,如果你同时打开了Web浏览器的多个窗口,每个窗口都是Web浏览器程序的不同进程。参见图15-1,这是同时打开多个计算器进程的例子。

图15-1 相同的计算器程序,六个正在运行的进程

每个进程可以有多个线程。不像线程,进程无法直接读写另一个进程的变量。如果你认为多线程程序是多个手指在追踪源代码,那么同一个程序打开多个进程就像有一个朋友拿着程序源代码的独立副本。你们都独立地执行相同的程序。

如果想在Python脚本中启动一个外部程序,就将该程序的文件名传递给subprocess.Popen()(在Windows中,右键点击该应用程序的开始菜单项,然后选择“属性”,查看应用程序的文件名。在OS X上,按住Ctrl键单击该应用程序并选择“显示包内容”,找到可执行文件的路径)。Popen()函数随后将立即返回。请记住,启动的程序和你的Python程序不在同一线程中运行。

在Windows计算机上,在交互式环境中输入以下代码:

>>> import subprocess
>>> subprocess.Popen('C:\\Windows\\System32\\calc.exe')
< subprocess.Popen object at 0x0000000003055A58>

在Ubuntu Linux上,可以输入以下代码:

>>> import subprocess
>>> subprocess.Popen('/usr/bin/gnome-calculator')
< subprocess.Popen object at 0x7f2bcf93b20>

在OS X上,过程稍有不同。参见15.8.5节“用默认应用程序打开文件”。

返回值是一个Popen对象,它有两个有用的方法:poll()和wait()。

可以认为poll()方法是问你的朋友,她是否执行完毕你给她的代码。如果这个进程在poll()调用时仍在运行,poll()方法就返回None。如果该程序已经终止,它会返回该进程的整数退出代码。退出代码用于说明进程是无错终止(退出代码为0),还是一个错误导致进程终止(退出代码非零,通常为1,但可能根据程序而不同)。

wait()方法就像是等着你的朋友执行完她的代码,然后你继续执行你的代码。wait()方法将阻塞,直到启动的进程终止。如果你希望你的程序暂停,直到用户完成与其他程序,这非常有用。wait()的返回值是进程的整数退出代码。

在Windows上,在交互环境中输入以下代码。请注意, wait()的调用将阻塞,直到退出启动的计算器程序。

❶ >>> calcProc = subprocess.Popen('c:\\Windows\\System32\\calc.exe')
❷ >>> calcProc.poll() == None
 True
❸ >>> calcProc.wait()
 0
 >>> calcProc.poll()
 0

这里,我们打开了计算器程序❶。在它仍在运行时,我们检查poll()是否返回None❷。它应该返回None,因为该进程仍在运行。然后,我们关闭计算器程序,并对已终止的进程调用wait()❸。wait()和poll()现在返回0,说明该进程终止且无错。

15.8.1 向Popen()传递命令行参数

用Popen()创建进程时,可以向进程传递命令行参数。要做到这一点,向Popen()传递一个列表,作为唯一的参数。该列表中的第一个字符串是要启动的程序的可执行文件名,所有后续的字符串将是该程序启动时,传递给该程序的命令行参数。实际上,这个列表将作为被启动程序的sys.argv的值。

大多数具有图形用户界面(GUI)的应用程序,不像基于命令行或基于终端的程序那样尽可能地使用命令行参数。但大多数GUI应用程序将接受一个参数,表示应用程序启动时立即打开的文件。例如,如果你使用的是Windows,创建一个简单的文本文件C:\hello.txt,然后在交互式环境中输入以下代码:

>>> subprocess.Popen(['C:\\Windows\\notepad.exe', 'C:\\hello.txt'])
< subprocess.Popen object at 0x00000000032DCEB8>

这不仅会启动记事本应用程序,也会让它立即打开C:\hello.txt。

15.8.2 Task Scheduler、launchd和cron

如果你精通计算机,可能知道 Windows 上的 Task Scheduler,OS X 上的launchd,或Linux上的cron调度程序。这些工具文档齐全,而且可靠,它们都允许你安排应用程序在特定的时间启动。如果想更多地了解它们,可以在http://nostarch. com/automatestuff/找到教程的链接。

利用操作系统内置的调度程序,你不必自己写时钟检查代码来安排你的程序。但是,如果只需要程序稍作停顿,就用time.sleep()函数。或者不使用操作系统的调度程序,代码可以循环直到特定的日期和时间,每次循环时调用time.sleep(1)。

15.8.3 用Python打开网站

webbrowser.open()函数可以从程序启动Web浏览器,打开指定的网站,而不是用subprocess.Popen()打开浏览器应用程序。详细内容参见第11章的“项目:利用webbrowser模块的mapIt.py”一节。

15.8.4 运行其他Python脚本

可以在Python中启动另一个Python脚本,就像任何其他的应用程序一样。只需向Popen()传入python.exe可执行文件,并将想运行的.py脚本的文件名作为它的参数。例如,下面代码将运行第1章的hello.py脚本:

>>> subprocess.Popen(['C:\\python34\\python.exe', 'hello.py'])
< subprocess.Popen object at 0x000000000331CF28>

向Popen()传入一个列表,其中包含Python可执行文件的路径字符串,以及脚本文件名的字符串。如果要启动的脚本需要命令行参数,就将它们添加列表中,放在脚本文件名后面。在Windows上,Python可执行文件的路径是C:\python34\ python.exe。在OS X上,是/Library/Frameworks/Python.framework/ Versions/3.3/bin/python3。在Linux上,是/usr/bin/python3。

不同于将Python程序导入为一个模块,如果Python程序启动了另一个Python程序,两者将在独立的进程中运行,不能分享彼此的变量。

15.8.5 用默认的应用程序打开文件

双击计算机上的.txt文件,会自动启动与.txt文件扩展名关联的应用程序。计算机上已经设置了一些这样的文件扩展名关联。利用Popen(),Python也可以用这种方式打开文件。

每个操作系统都有一个程序,其行为等价于双击文档文件来打开它。在Windows上,这是start程序。在OS X上,这是open程序。在Ubuntu Linux上,这是see程序。在交互式环境中输入以下代码,根据操作系统,向Popen()传入'start'、'open'或'see':

>>> fileObj = open('hello.txt', 'w') >>> fileObj.write('Hello world!') 12 >>> fileObj.close() >>> import subprocess >>> subprocess.Popen(['start', 'hello.txt'], shell=True)

这里,我们将Hello world!写入一个新的hello.txt文件。然后调用Popen(),传入一个列表,其中包含程序名称(在这个例子中,是Windows上的'start'),以及文件名。我们也传入了shell=True关键字参数,这只在Windows上需要。操作系统知道所有的文件关联,能弄清楚应该启动哪个程序,比如Notepad.exe,来处理hello.txt文件。

在OS X上,open程序用于打开文档文件和程序。如果你有Mac,在交互式环境中输入以下代码:

>>> subprocess.Popen(['open', '/Applications/Calculator.app/'])
< subprocess.Popen object at 0x10202ff98>

计算器应用程序应该会打开。

Unix哲学

程序精心设计,能被其他程序启动,这样的程序比单独使用它们自己的代码更强大。Unix的哲学是一组由UNIX操作系统(现代的Linux和OS X也是基于它)的程序员建立的软件设计原则。它认为:编写小的、目的有限的、能互操作的程序,胜过大的、功能丰富的应用程序。

较小的程序更容易理解,通过能够互操作,它们可以是更强大的应用程序的构建块。智能手机应用程序也遵循这种方式。如果你的餐厅应用程序需要显示一间咖啡店的方位,开发者不必重新发明轮子,编写自己的地图代码。餐厅应用程序只是启动一个地图应用程序,同时传入咖啡店的地址,就像Python代码调用一个函数,并传入参数一样。

你在本书中编写的Python程序大多符合Unix哲学,尤其是在一个重要的方面:它们使用命令行参数,而不是input()函数调用。如果程序需要的所有信息都可以事先提供,最好是用命令行参数传入这些信息,而不是等待用户键入它。这样,命令行参数可以由人类用户键入,也可以由另一个程序提供。这种互操作的方式,让你的程序可以作为另一个程序的部分而复用。

唯一的例外是,你不希望口令作为命令行参数传入,因为命令行可能记录它们,作为命令历史功能的一部分。在需要输入口令时,程序应该调用input()函数。

https://en.wikipedia.org/wiki/Unix_philosophy/,你可以阅读更多有关Unix哲学的内容。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文