python使用subprocess模块运行其他程序并获取输出及结果

先说说背景。

这几天项目中遇到一个签名的算法,没有相应的python库,自己去实现又比较费时间。

中间的过程是这样的。

经过查找发现这个开源项目本身支持一个JavaScript的SDK,里面已经实现了必须的功能。大概试了一下写了几个简单的js脚本,就实现了所需要的基本功能。既然js脚本很容易就实现了需要的功能,为了方便(其实是因为我懒,懒得去自己用python再实现内容转换和签名的算法了)就决定使用python调用已经写好的js脚本,获取脚本的输出来做为结果,在解析整理下就可以了。

思路有了,下面就是如何用python的实现程序的调用和获取结果了。

看了下有些人使用os模块提供的函数,类似os.system, os.spawn族的函数(其实就是Linux下相应的C的API)。但是觉得太底层了,而且有些还只能在特定的平台上使用。就没有使用这种方法。转而找到了subprocess库(终于进入正题了)。

去官方的文档看了下描述,发现就是用来代替os.system,os.spawn族之类的

This module intends to replace several older modules and functions:

os.system

os.spawn*

我的需求很容易就满足了,使用subproces的run方法获取输出和返回值。

然后,又好奇了两个问题:

第一,如何实时的获取程序的输出。当程序会运行相当长一段时间,或者有很大量的输出的时候

第二,如何改变程序的运行环境

首先说第一个问题。我现在官方文档上找了下。发现似乎可以使用Popen类来实现。文档里面说到的跟输出相关的有两个,一个是Popen.communicate方法,一个是Popen的stdout属性。两者的描述很容易再官文上找到就不贴了。大概说一下就是官方推荐使用communicate方法来跟运行的子进程进行交互。

我就试了一下communicate方法,包括timeout参数。

发现下面的几点:

1.communicate在不设置timeout的时候,会一直block,直到子进程运行完。

2.communicate再设置了timeout参数,并且捕获了TimeoutExpired事件之后,获取的out是空的,并且子程序还在继续运行没有收到影响

总结一下就是,使用communicate你必须等到程序运行完之后才能够一次性获取全部的输出。运行过程中,程序的输出是暂存在内存里面的。所以在communicate的描述后面特别说明了,如果输出较大的时候,不要使用这个函数。

之后,就看了stdout,stdin之类的属性,也发现一个警告说可能引起死锁之类的。然后Google了一下。发现还是很多人在用stdout这个属性的。当然用法就是把它当作一个打开的文件对象。使用readline方法不断获取程序的输出,但是在每个readline的调用中,依然是block的。

总结一下,关于第一个问题。如果子进程的运行时间有限,输出的内容也比较少的情况下,使用communicate方法比较合适。还有一种情况就是要限制子进程的运行时间,这个时候可以用communicate的timeout参数,并在timeout时间的处理中kill掉子进程。如果程序运行时间长,需要实时的获取输出,或者输出比较多的情况下,就使用stdout这样的属性,不断调用readline获取输出就好。

然后关于第二个问题。其实使用Popen类就可以完美解决,Popen类的cwd参数用来设定子进程的工作目录,还有env参数用来设定子进程运行的环境变量。基本上就可以满足我们的使用中的大部分场景了。

今天就先好奇这些吧,后面有时间遇到再继续挖。

你可能感兴趣的:(python,subprocess,python)