2014-12-21 53 views
0

我想了解Python的子进程模块是如何工作的,并且已经开始设置自己的一些问题,这些问题并不像我想的那么简单。具体来说,我试图与已经创建为子流程的Python intepreter进行交互。在使用Python的子进程模块作为子进程运行Python解释器时遇到问题

我创建了一个测试模块,dummy.py即结构如下:

def hi(): 
    print "Hi Earth" 


hi() 

然后,测试我使用的子模块的能力,我写了一个名为pyrun.py模块,其被构造如下:

import subprocess 

def subprocess_cmd1(): 
    outFile = open("tempy1.tmp",'w') 
    proc = subprocess.Popen("pwd", stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True) 
    outFile.close() 

def subprocess_cmd2(): 
    outFile = open("tempy2.tmp",'w') 
    proc = subprocess.Popen('python dummy.py', stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True) 
    outFile.close() 

def subprocess_cmd3(): 
    outFile = open("tempy3.tmp",'w') 
    proc = subprocess.Popen('python', stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True) 
    proc.communicate('import dummy') 
    outFile.close() 

def subprocess_cmd4(): 
    outFile = open("tempy4.tmp",'w') 
    proc = subprocess.Popen('python', stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True) 
    proc.communicate('import dummy') 
    proc.communicate('dummy.hi()') 
    outFile.close() 

print "Start" 
subprocess_cmd1() 
subprocess_cmd2() 
subprocess_cmd3() 
subprocess_cmd4() 
print "Stop" 

的想法是从调用进程发送输入到子进程,并已全部输出发送到一个文本文件中。

当我尝试在命令行中运行pyrun,我得到如下结果:

[email protected]:~/Projects/LushProjects/newCode$ python pyrun.py 
Start 
Traceback (most recent call last): 
    File "pyrun.py", line 42, in <module> 
    subprocess_cmd4() 
    File "pyrun.py", line 35, in subprocess_cmd4 
    proc.communicate('dummy.hi()') 
    File "/usr/lib/python2.7/subprocess.py", line 785, in communicate 
    self.stdin.write(input) 
ValueError: I/O operation on closed file 

subprocess_cmd1 - 3运行没有崩溃。错误进来subprocess_cmd4(),试图执行该语句时:

proc.communicate('dummy.hi()') 

这似乎是因为communicate方法关闭管道stdin它是第一次使用后。它为什么这样做?假设管道应该关闭有什么好处吗?

而且,当我看着tempy3.tmp(为subprocess_cmd3我的输出文件),它缺少Python解释器的“启动”文本的内容 - 即

Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 

这是为什么?我重定向stdout & stderroutFile

最后,为什么tempy4.tmp完全空?它至少不应该包含在它坠毁之前发送给它的文本? (即它应该看起来很像tempy3.tmp

+0

无关:为什么要使用子进程来运行Python代码? – jfs

+0

@ J.F.Sebastien - 我真的只是试验子过程,看看我是否理解如何使用它以及它是如何工作的。我想一个更现实的例子就是使用它来在其他语言的解释器中运行代码。 – user1245262

+0

如果它是一个学习exersice那么这里有一些提示:1.避免'shell = True',使用列表参数来传递命令2.知道如果一个子进程的stdin/stdout/stderr被重定向(例如,在输出中抑制颜色(ansi代码)),或者在'python'中没有标题。 – jfs

回答

1

问题是你如何使用subprocess.communicate(),它需要一个字符串。从文档

https://docs.python.org/2/library/subprocess.html

与互动的过程:将数据发送至标准输入。从stdout和 stderr中读取数据,直到达到文件结束。等待进程终止。 可选输入参数应该是要发送给子进程 进程的字符串,如果没有数据应发送给子进程,则为无。

试试这个:

def subprocess_cmd4(): 
    outFile = open("tempy4.tmp",'w') 
    proc = subprocess.Popen('python', stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True) 
    proc.communicate('import dummy\ndummy.hi()\n') 
    outFile.close() 
+0

感谢。我遇到了一个不同的解决方案,我为每一行提供给解释器的每一行都使用了proc.stdin.write('.... \ n')。但是我仍然想知道关闭管道沟通的优势是什么,Python解释器的“介绍”文本去了哪里? – user1245262

+0

@ user1245262:引自文档:*“等待进程终止。” * - 没有一点叫'沟通()' - 子进程已经死亡。 *“在哪里从Python解释器的‘介绍’的文字去吗?” * - Python没有在非交互模式进行打印(如果标准输入未连接到TTY)。 – jfs

+0

@ user1245262:^^^^^“不止一次调用'communicate()'”** ** – jfs

0

回答你的问题有关communicate()

communicate()只能使用一次,因为在第一次通信后被调用的outFile已被关闭。再次调用communicate()将永远不会产生任何内容,因为您已经读取了前一个中的所有输出。使用它的一个优点是,您在使用它之后不需要终止。

回答您关于tempy3.py中的python命令的标题在哪里的问题。

这只是python的头文件,并不是'问题'的'答案'。你只是简单地进入python模式,不要求任何回应。 然而,如果你尝试:

proc.communicate('1+1') 

那么就应该写2到文件tempy4.tmp,对不对?

。这是因为communicate()只能从Unix命令行输出,而不是python。例如

proc = subprocess.Popen('ls', stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True) 
proc.communicate('-l') 

输出:

[email protected]:~/Desktop/Testing$ pg tempy4.tmp         
dummy.py 
dummy.pyc 
pyrun.py 
tempy1.tmp 
tempy2.tmp 
tempy3.tmp 
tempy4.tmp 

我跑你的程序,因为它是和tempy4.tmp实际显示Hi Earth一次,有你已经把同样的错误。但是,如果你摆脱第二communicate(),并只有一个,你可以做@ user590028指出:

proc.communicate('import dummy\ndummy.hi()\n') 

然而,而不必编成一行的所有命令,子进程可以让你做到这一点与stdin.write

proc.stdin.write('import dummy\n') 
proc.communicate('dummy.hi()') 

*确保你把你的\n命令后的新行。 他们都输出:

Hi Earth 
Hi Earth 
+0

1.您甚至可以在调用.communicate()之前关闭outFile,后立即'POPEN()'(子进程都有自己的副本)2.'.communicate()'等待子进程来完成,即,子进程已经被时间'.communicate()'返回收获。 3.有关'tempy3.py'标题的解释不正确。 python不以非交互模式打印标题(标准输入不是tty)。 '-i'选项可以强制交互模式。 – jfs

0

定义你的解释:

interpreter=sys.executable 

,并通过列表的第一个参数:

fproc=subprocess.Popen([interpreter,script,'-f',datafile], stdout=subprocess.PIPE)