【问题标题】:Having trouble running Python interpreter as a subprocess using Python's subprocess module使用 Python 的子进程模块将 Python 解释器作为子进程运行时遇到问题
【发布时间】:2014-12-21 17:40:53
【问题描述】:

我试图了解 Python 的 subprocess 模块是如何工作的,并开始给自己设置一些不像我想象的那么简单的问题。具体来说,我正在尝试与作为子进程创建的 Python 解释器进行交互。

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

def hi():
    print "Hi Earth"


hi()

然后,为了测试我使用 subprocess 模块的能力,我编写了一个名为 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 时,我得到以下结果:

me@Bedrock1:~/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.

这是为什么呢?我将 both stdoutstderr 重定向到 outFile

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

【问题讨论】:

标签: python python-2.7 subprocess


【解决方案1】:

定义你的解释器:

interpreter=sys.executable

并传递一个列表作为第一个参数:

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

【讨论】:

    【解决方案2】:

    问题在于您如何使用subprocess.communicate(),它需要一个字符串。来自文档

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

    与进程交互:将数据发送到标准输入。从标准输出读取数据并 stderr,直到到达文件结尾。等待进程终止。 可选的输入参数应该是一个要发送给孩子的字符串 进程,或者 None,如果不应该向孩子发送数据。

    试试这个:

    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()
    

    【讨论】:

    • 谢谢。我遇到了一个不同的解决方案,我只对提供给解释器的每一行使用了 proc.stdin.write('....\n') 。但我仍然想知道关闭管道进行通信有什么好处,Python 解释器的“介绍”文本去哪儿了?
    • @user1245262:引用自文档:“等待进程终止。” -- 没有必要调用 communicate() -- 子进程已经死了. “Python 解释器中的‘intro’文本去哪儿了?” -- python 不会在非交互模式下打印它(如果 stdin 没有连接到 tty)。
    • @user1245262: ^^^^^ "没有必要打电话给communicate()" 不止一次
    【解决方案3】:

    回答你关于communicate()的问题。

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

    回答您关于tempy3.pypython 命令的标头在哪里的问题。

    这只是 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')
    

    输出:

    student@ubuntu:~/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')
    

    但是,subprocess 允许您使用 stdin.write 来执行此操作,而不是将所有命令集中在一行中:

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

    *确保将\n 放在命令后换行。 他们都输出:

    Hi Earth
    Hi Earth
    

    【讨论】:

    • 1.您甚至可以在调用.communicate() 之前关闭outFile -- 在Popen() 之后立即关闭(子进程有自己的副本) 2. .communicate() 等待子进程完成,即此时子进程已经被收割.communicate() 返回。 3.关于tempy3.py header 的解释不正确。 python 不在非交互模式下打印标题(stdin 不是 tty)。 -i 选项可以强制交互模式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 1970-01-01
    • 2015-08-05
    相关资源
    最近更新 更多