python子程序:Python程式代碼段中調用另一Python程式代碼檔案(啟動子程序)
- python子程序:在一段Python程式(python代碼段)中調用另一Python程式(python代碼檔案)
-
- 一. 閑言多說
- 二. 主要function
-
- 2.1 Popen
- 三. code
-
- 3.1 假定子程序檔案(代碼)如下(sys_test_map.py):
- 3.2 母程式代碼如下:
- 3.3 總結
- 四. 寫在最後
python子程序:在一段Python程式(python代碼段)中調用另一Python程式(python代碼檔案)
一. 閑言多說
在資料模組化的生産部署階段,有時候為了結果的實時性,我們需要實時調用模型檔案進行結果輸出。
這裡假定一個業務場景:
某py代碼片段的目标是進行房價預測,在代碼片段中調用“模型預測.py”(作為子程序),根據輸入參數由模型代碼給出預測房價,目前代碼片段擷取模型預測輸出,對其進行二次處理後生成json格式集返給下遊處理環節。
二. 主要function
這裡使用Python 标準庫裡的 subprocess.Popen() 類進行處理。
常用的 os.system、os.spawn*、os.popen*、popen2*、commands.*等子產品均可由subprocess子產品替代。
subprocess提供了一組啟動子程序的友善的标準函數: subprocess.call()等
但是由于業務場景的複雜性,這種友善函數有時候不能很好的達到我們的目的,故而推薦使用: subprocess.Popen()
2.1 Popen
Popen class:在新的程序中執行子程式,它提供了比友善函數 subprocess.call()等更高的靈活性,友善覆寫更多的使用情景。
subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None,
universal_newlines=False, startupinfo=None, creationflags=0)
這裡介紹其中幾個關鍵參數:
- args: 待執行的程式(代碼段),是一段字元串或者是程式及參數的序列,推薦使用序列的形式進行。
- stdout: 如果stdout=subprocess.PIPE,stdout作為一個檔案對象存在,用于獲得子程序的輸出。如果stdout=None,stdout是None。stderr參數類似。
介紹一個Popen class的methods:
-
Popen.communicate(input=None): 等待程序終止後,從Popen的stdout和stderr讀取資料,擷取檔案從頭到末尾的所有輸出。可選 input 參數是要發送給子程序的字元串,如果不發送資料給子程序,則将其置為None。
如果要讀取資料,需要将:stderr 和 stdout的值置為:subprocess.PIPE
如果要傳入資料,需要将:stdin的值置為:subprocess.PIPE
傳回值為:tuple, (stdout, stderr)
注:communicate()讀取成功的資料會被緩存在記憶體中,是以當需要讀取的資料太大,慎用此方法。 本案例中,要讀取資料量很小,是以采用了這種方法。 注:使用communicate() 替代 stdout.read() or stdout.readlines() 可以避免由于其它OS pipe緩沖區被填滿并阻塞子程序而導緻的死鎖。
三. code
3.1 假定子程序檔案(代碼)如下(sys_test_map.py):
testmap = {}
testmap['name'] = 'zhangsan'
testmap['age'] = 18
testmap['edu'] = {'school': 'college', 'year': 2018}
print testmap
a = {
u'beijing': 0.99892587165634505,
u'shanghai': 0.0014163851986520321,
u'shenzhen': 0.9990925714738389,
u'tianjin': 0.00020464026986137315,
u'hegang': 0.99917447530410486}
print a
上述代碼片段會輸出兩個dict,這兩個dict,将會被我用communicate()方法擷取到。
3.2 母程式代碼如下:
import os
import sys
import subprocess
from pprint import pprint
# 建立子程序
subp = subprocess.Popen(['python', os.path.join(os.getcwd(), 'sys_test_map.py')],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 擷取Popen.communicate(), return tuple(stdout, stderr)
cmnce = subp.communicate()
print 'the value of cmnce is: ', pprint(cmnce)
subprocess_stdout = cmnce[0].strip('\n')
subprocess_stderr = cmnce[1].strip('\n')
# 将子程序的最後一個輸出激活成特定的object
result_dict = eval(str(subprocess_stdout.split('\n')[-1]))
print type(result_dict)
pprint(result_dict)
程式執行結果:
1.從子程序擷取的值(communicate() return):
the value of cmnce is:
("{'age': 18, 'name': 'zhangsan', 'edu': {'school': 'college', 'year': 2018}}\r\n
{u'tianjin': 0.00020464026986137315,
u'beijing': 0.998925871656345,
u'shanghai': 0.0014163851986520321,
u'hegang': 0.9991744753041049,
u'shenzhen': 0.9990925714738389}\r\n",
'')
對象類型為: <type 'tuple'>
1.1 其中stdout值:
"{'age': 18, 'name': 'zhangsan', 'edu': {'school': 'college', 'year': 2018}}\r\n
{u'tianjin': 0.00020464026986137315, u'beijing': 0.998925871656345, u'shanghai': 0.0014163851986520321, u'hegang': 0.9991744753041049, u'shenzhen': 0.9990925714738389}\r\n"
1.2 其中stderr值:
當未發生error時,傳回None
2.eval()後的函數對象:
- 對象類型:
<type 'dict'>
- dict對象值:
{ u'beijing': 0.998925871656345, u'hegang': 0.9991744753041049, u'shanghai': 0.0014163851986520321, u'shenzhen': 0.9990925714738389, u'tianjin': 0.00020464026986137315 }
3.3 總結
subprocess.Popen()可以很好的實作py代碼中子程序的啟動并擷取子程序傳回值
四. 寫在最後
筆者還是菜鳥一枚,不敢高談教化,隻求将自己的了解能解釋清楚。
讀到此處的您,如果我的了解對解答您的問題有所幫助,那我将是很開心的。
能力一般,水準有限,可優化的地方千千…請指正!
祝好!