利用内建的 subprocess
模块中的 Popen()
函数,
Python
程序可以启动计算机中的其他程序( Popen()
函数名中的P
表示 process
,进程)。
如果打开了一个应用程序的多个实例,
每个实例都是同一个程序的不同进程。例如,
如果同时打开了Web
浏览器的多个窗口,每个窗口都是 Web
浏览器程序的不同进程。
每个进程可以有多个线程。不像线程,进程无法直接读写另一个进程的变量。 如果认为多线程程序是多个手指在追踪源代码, 那么同一个程序打开多个进程就像有一个朋友拿着程序源代码的独立副本。 都独立地执行相同的程序。
如果想在 Python
脚本中启动一个外部程序,
就将该程序的文件名传递给subprocess.Popen()
(在 Windows 中,右键点击该应用程序的开始菜单项,
然后选择“属性”,查看应用程序的文件名。在 OS X 上,
按住 Ctrl 键单击该应用程序并选择
“显示包内容”,找到可执行文件的路径)。Popen()
函数随后将立即返回。
请记住,启动的程序和Python程序不在同一线程中运行。
在Windows计算机上,在交互式环境中输入以下代码:
import subprocess
subprocess.Popen( 'C:\\Windows\\System32\\calc.exe')
在 UbuntuLinux 上,可以输入以下代码:
import subprocess
subprocess.Popen('/usr/bin/gnome-calculator')
在 OS X 上,过程稍有不同。
返回值是一个 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
calcProc.wait()
calcProc.poll()
这里打开了计算器程序。在它仍在运行时,检查 polio
是否返回None
。
它应该返回 None
, 因为该进程仍在运行。关闭计算器程序,
并对已终止的进程调用wait()
。wait()
和poll()
现在返回0,说明该进程终止且无错。
向 Popen()
传递命令行参数
用Popen()
创建进程时,可以向进程传递命令行参数。
要做到这一点,向Popen()
传递一个列表,作为唯一的参数。
该列表中的第一个字符串是要启动的程序的可执行文件名,所有后续的字符串将是该程序启动时,
传递给该程序的命令行参数。实际上,这个列表将作为被启动程序的sys.argv
的值。
大多数具有图形用户界面(GUI
)的应用程序,
不像基于命令行或基于终端的程序那样尽可能地使用命令行参数。
但大多数 GUI
应用程序将接受一个参数,
表示应用程序启动时立即打开的文件。例如,如果使用的是 Windows
,创建一个简单的文本文件 C:\\hello.txt
,
在交互式环境中输入以下代码:
subprocess.Popen( ['C:\\Windows\\notepad.exe','C:\\hello.txt'])
这不仅会启动记事本应用程序,
也会让它立即打开 C:\\hello.txt
。
Task Scheduler
、launchd
和 cron
如果精通计算机,可能知道Windows上的
Task Scheduler
,OS X 上的launchd
,
或 Linux 上的 cron
调度程序。这些工具文档齐全,
而且可靠,它们都允许安排应用程序在特定的时间启动。
如果想更多地了解它们,http://nostarch.com/automatestuff/
找到教程的链接。
利用操作系统内置的调度程序,不必自己写时钟检查代码来安排程序。
但是,如果只需要程序稍作停顿,就用 time.sleep()
函数。
或者不使用操作系统的调度程序,
代码可以循环直到特定的日期和时间,每次循环时调用 time.sleep(1)
。
webbrowser.open()
函数可以从程序启动 Web 浏览器,
打开指定的网站,而不是用 subprocess.Popen()
打开浏览器应用程序。
subprocess.Popen( ['C:\\python34\\python.exe', 'hello.py'])
向 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程序, 两者将在独立的进程中运行, 不能分享彼此的变量。
fileObj = open('xx_hello.txt', 'w')
fileObj .write('Hello world!')
12
fileObj.close()
import subprocess
subprocess.Popen(['start', 'hello.txt'], shell=True)
hello.txt: 1: start: not found
<Popen: returncode: None args: ['start', 'hello.txt']>
这里将Hello world!
写入一个新的hello.txt
文件。
然后调用Popen()
,传入一个列表,其中包含程序名称(在这个
例子中,是 Windows 上的'start'
),以及文件名。也
传入了shelHTme
关键字参数,这只在Windows上需要。
操作系统知道所有的文件关联,能弄清楚应该启动哪个程序,
比如Notepad.exe
,来处理hello.txt
文件。
在OS X上,open
程序用于打开文档文件和程序。
如果有Mac
,在交互式环境中输入以下代码:
subprocess.Popen(['open','/Applications/Calculator.app/'])
计算器应用程序应该会打开。
Unix哲学
程序精心设计,能被其他程序启动,这样的程序比单独使用它们自己的代码更强大。 Unix的哲学是一组由UNIX操作系统(现代的Linux和OS X也是基于它)的程序员建立的软件设计原则。 它认为:编写小的、目的有限的、能互操作的程序, 胜过大的、功能丰富的应用程序。
较小的程序更容易理解,通过能够互操作,它们可以是更强大的应用程序的构建块。 智能手机应用程序也遵循这种方式。如果餐厅应用程序需要显示一间咖啡店的方位, 开发者不必重新发明轮子,编写自己的地图代码。餐厅应用程序只是启动一个地图应用程序, 同时传入咖啡店的地址,就像Python代码调用一个函数,并传入参数一样。
Python程序大多符合 Unix
哲学,
尤其是在一个重要的方面:它们使用命令行参数,而不是 input()
函数调用。
如果程序需要的所有信息都可以事先提供,最好是用命令行参数传入这些信息,
而不是等待用户键入它。这样,命令行参数可以由人类用户健入,
也可以由另一个程序提供。这种互操作的方式,让程序可以作为另一个程序的部分而复用。
唯一的例外是,不希望口令作为命令行参数传入,
因为命令行可能记录它们,作为命令历史功能的一部分。
在需要输入口令时,程序应该调用 input()
函数。
在这方面,有一本著名的书《UNIX编程艺术》,可以深入阅读。