天天看點

python子程序:在python程式代碼中調用另一段python程式代碼檔案(啟動子程序)python子程序:在一段Python程式(python代碼段)中調用另一Python程式(python代碼檔案)

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)
           

這裡介紹其中幾個關鍵參數:

  1. args: 待執行的程式(代碼段),是一段字元串或者是程式及參數的序列,推薦使用序列的形式進行。
  2. stdout: 如果stdout=subprocess.PIPE,stdout作為一個檔案對象存在,用于獲得子程序的輸出。如果stdout=None,stdout是None。stderr參數類似。

介紹一個Popen class的methods:

  1. 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代碼中子程序的啟動并擷取子程序傳回值

四. 寫在最後

筆者還是菜鳥一枚,不敢高談教化,隻求将自己的了解能解釋清楚。

讀到此處的您,如果我的了解對解答您的問題有所幫助,那我将是很開心的。

能力一般,水準有限,可優化的地方千千…請指正!

祝好!

繼續閱讀