subprocessを使って外部プログラムを実行する
https://docs.python.jp/3/library/subprocess.html
subprocessには色々な関数が定義されているのでとりあえずいくつか使いそうなものを試してみます。
例としてPythonから別のPythonのプログラムを実行する処理を実装してみます。
subprocess.check_callによる簡易的な外部プログラムの実行
まずtest.pyを用意します。
# -- test.py -- from time import sleep print('child start!') sleep(1) print('child end!')
これをmain.pyから実行してみます。
# -- main.py -- import subprocess print('parent start!') subprocess.check_call(['python','test.py']) print('parent end!')
$ py main.py parent start! child start! child end! parent end!
check_allは子プロセス(test.py)の終了をまってから次の処理へ進みます。
また外部プログラム側で何かしら例外で終了した場合はcheck_callでも例外を投げます。
# -- error.py -- raise Exception('error test!')
# -- main.py -- import subprocess print('parent start!') subprocess.check_call(['python','error.py']) print('parent end!')
$ py main.py parent start! Traceback (most recent call last): File "error.py", line 1, in <module> raise Exception('error test!') Exception: error test! Traceback (most recent call last): File "main.py", line 8, in <module> ps = subprocess.check_call(['python','error.py']) File "F:\Python36\lib\subprocess.py", line 291, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command '['python', 'error.py']' returned non-zero exit status 1.
subprocess.check_outputで実行されたプログラムの標準出力を得る
check_callと違い、こちらは外部プログラムで実行された標準出力を実行側で文字列で取得することができます。
# -- test.py -- from time import sleep print('child start!') sleep(1) print('child end!')
# -- main.py -- import subprocess output = subprocess.check_output(['python','test.py']) print('---') print(output.decode('sjis'))
$ py main.py --- child start! child end!
ちなみにcheck_outputの戻り値はバイナリ文字列になってるのでdecodeで文字列化してから出力してます。
subprocess.runによる外部プログラムの実行
Python3.5以上からはcheck_callやcheck_outputよりも柔軟なrunを使うこともできます。
check_callをrunで置き換えると以下のようになります。
import subprocess print('parent start!') subprocess.run(['python','test.py'], check=True) print('parent end!')
check_outputをrunで置き換えると以下のようになります。
import subprocess output = subprocess.run(['python','test.py'], check=True, stdout=subprocess.PIPE).stdout print(output.decode('sjis'))
他にも色々できるようですが、ここでは割愛。
目的がハッキリしている場合はcheck_callやcheck_outputでも良さそうですね。
subprocess.Popenによる詳細な外部プログラムの実行
通常ではcheck_allやcheck_output(およびrun)などを使えばそれで基本的には問題がでることはありませんが、例えば子プロセスの終了をまたずに何か処理をしたいとかそういうことをしたい場合にはPopenを使います。
# -- test.py -- from time import sleep print('child start!') sleep(1) print('child end!')
# -- main.py -- import subprocess print('parent start!') ps = subprocess.Popen(['python','test.py']) print('parent end!')
$ py main.py parent start! parent end! child start! child end!
このように子プロセスの終了をまたずに「parent end!」が出力されていますね。