2014-12-21 89 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)