サブプロセスを使用してPython3で外部プログラムを実行する方法
序章
Python 3には、外部プログラムを実行し、Pythonコードでそれらの出力を読み取るためのサブプロセスモジュールが含まれています。
あなたが見つけるかもしれません subprocess
Pythonコード内からコンピューター上で別のプログラムを使用する場合に便利です。 たとえば、Pythonコード内から git を呼び出して、プロジェクト内で追跡されているファイルを取得したい場合があります。 git
バージョン管理。 あなたがあなたのコンピュータでアクセスできるどんなプログラムもによって制御されることができるので subprocess
、ここに示す例は、Pythonコードから呼び出す可能性のあるすべての外部プログラムに適用できます。
subprocess
いくつかのクラスと関数が含まれていますが、このチュートリアルでは、 subprocess
の最も便利な関数:subprocess.run。 そのさまざまな使用法と主なキーワード引数を確認します。
前提条件
このチュートリアルを最大限に活用するには、Python3でのプログラミングにある程度精通していることをお勧めします。 必要な背景情報については、次のチュートリアルを確認できます。
外部プログラムの実行
あなたは使用することができます subprocess.run
Pythonコードから外部プログラムを実行する関数。 ただし、最初に、をインポートする必要があります subprocess
と sys
プログラムへのモジュール:
import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "print('ocean')"])
これを実行すると、次のような出力が表示されます。
Outputocean
この例を確認してみましょう。
- sys.executable は、プログラムが最初に呼び出されたPython実行可能ファイルへの絶対パスです。 例えば、
sys.executable
次のようなパスかもしれません/usr/local/bin/python
. subprocess.run
実行しようとしているコマンドのコンポーネントで構成される文字列のリストが表示されます。 最初に渡す文字列はsys.executable
、私たちは指示していますsubprocess.run
新しいPythonプログラムを実行します。- The
-c
コンポーネントはpython
実行するPythonプログラム全体で文字列を渡すことができるコマンドラインオプション。 この場合、文字列を出力するプログラムを渡しますocean
.
あなたは私たちが渡すリストの各エントリについて考えることができます subprocess.run
スペースで区切られているように。 例えば、 [sys.executable, "-c", "print('ocean')"]
大まかに次のように変換されます /usr/local/bin/python -c "print('ocean')"
. ご了承ください subprocess
基盤となるオペレーティングシステムで実行する前に、コマンドのコンポーネントを自動的に引用符で囲みます。たとえば、スペースを含むファイル名を渡すことができます。
警告:信頼できない入力をに渡さないでください subprocess.run
. 以来 subprocess.run
コンピュータ上で任意のコマンドを実行する機能があり、悪意のある攻撃者がそれを使用して予期しない方法でコンピュータを操作する可能性があります。
外部プログラムからの出力のキャプチャ
これで、を使用して外部プログラムを呼び出すことができます subprocess.run
、そのプログラムからの出力をキャプチャする方法を見てみましょう。 たとえば、このプロセスは、 git ls-files
現在バージョン管理下に保存されているすべてのファイルを出力します。
注:このセクションに示されている例には、Python3.7以降が必要です。 特に、 capture_output
と text
キーワード引数は、2018年6月にリリースされたPython3.7で追加されました。
前の例に追加しましょう:
import subprocess
import sys
result = subprocess.run(
[sys.executable, "-c", "print('ocean')"], capture_output=True, text=True
)
print("stdout:", result.stdout)
print("stderr:", result.stderr)
このコードを実行すると、次のような出力が返されます。
Outputstdout: ocean
stderr:
この例は、最初のセクションで紹介した例とほぼ同じです。印刷するサブプロセスをまだ実行しています ocean
. 重要なのは、しかし、私たちは合格します capture_output=True
と text=True
キーワード引数 subprocess.run
.
subprocess.run
にバインドされているsubprocess.CompletedProcessオブジェクトを返します result
. The subprocess.CompletedProcess
オブジェクトには、外部プログラムの終了コードとその出力に関する詳細が含まれています。 capture_output=True
を保証します result.stdout
と result.stderr
外部プログラムからの対応する出力が入力されます。 デフォルトでは、 result.stdout
と result.stderr
バイトとしてバインドされますが、 text=True
キーワード引数は、代わりにバイトを文字列にデコードするようにPythonに指示します。
出力セクションでは、 stdout
は ocean
(さらに、末尾の改行 print
暗黙的に追加します)、 stderr
.
空でない値を生成する例を試してみましょう stderr
:
import subprocess
import sys
result = subprocess.run(
[sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True
)
print("stdout:", result.stdout)
print("stderr:", result.stderr)
このコードを実行すると、次のような出力が返されます。
Outputstdout:
stderr: Traceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: oops
このコードはPythonサブプロセスを実行し、すぐに ValueError
. 決勝戦を検査するとき result
、何も表示されません stdout
と Traceback
私たちの ValueError
の stderr
. これは、デフォルトでPythonが書き込みを行うためです。 Traceback
未処理の例外の stderr
.
不正な終了コードで例外を発生させる
実行するプログラムが不正な終了コードで終了した場合に、例外を発生させると便利な場合があります。 ゼロコードで終了するプログラムは成功したと見なされますが、ゼロ以外のコードで終了するプログラムはエラーが発生したと見なされます。 例として、このパターンは、実行した場合に例外を発生させたい場合に役立ちます。 git ls-files
実際にはそうではなかったディレクトリ内 git
リポジトリ。
使用できます check=True
キーワード引数 subprocess.run
外部プログラムがゼロ以外の終了コードを返した場合に例外を発生させるには、次のようにします。
import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)
このコードを実行すると、次のような出力が返されます。
OutputTraceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: oops
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.8/subprocess.py", line 512, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.
この出力は、エラーを発生させたサブプロセスを実行したことを示しています。 stderr
私たちのターミナルで。 それで subprocess.run
忠実に育てた subprocess.CalledProcessError
私たちのメインのPythonプログラムに代わって。
または、 subprocess
モジュールには、 subprocess.CompletedProcess.check_returncode メソッドも含まれています。これは、同様の効果を得るために呼び出すことができます。
import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"])
result.check_returncode()
このコードを実行すると、次のようになります。
OutputTraceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: oops
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode
raise CalledProcessError(self.returncode, self.args, self.stdout,
subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.
合格しなかったので check=True
に subprocess.run
、正常にバインドしました subprocess.CompletedProcess
インスタンスから result
プログラムがゼロ以外のコードで終了した場合でも。 呼び出し result.check_returncode()
ただし、 subprocess.CalledProcessError
完了したプロセスが不正なコードで終了したことを検出するためです。
タイムアウトを使用してプログラムを早期に終了する
subprocess.run
が含まれています timeout
実行に時間がかかりすぎる場合に外部プログラムを停止できるようにする引数:
import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=1)
このコードを実行すると、次のような出力が返されます。
OutputTraceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.8/subprocess.py", line 491, in run
stdout, stderr = process.communicate(input, timeout=timeout)
File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate
stdout, stderr = self._communicate(input, endtime, timeout)
File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate
self.wait(timeout=self._remaining_time(endtime))
File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait
return self._wait(timeout=timeout)
File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait
raise TimeoutExpired(self.args, timeout)
subprocess.TimeoutExpired: Command '['/usr/local/bin/python', '-c', 'import time; time.sleep(2)']' timed out after 0.9997982999999522 seconds
実行しようとしたサブプロセスは、time.sleep関数を使用してスリープしました 2
秒。 しかし、私たちは合格しました timeout=1
キーワード引数 subprocess.run
後にサブプロセスをタイムアウトします 1
2番目。 これは、私たちが subprocess.run
最終的に上げた subprocess.TimeoutExpired
例外。
に注意してください timeout
キーワード引数 subprocess.run
おおよそです。 Pythonは、サブプロセスの後にサブプロセスを強制終了するために最善を尽くします timeout
秒数ですが、必ずしも正確であるとは限りません。
プログラムへの入力の受け渡し
プログラムは、入力が経由で渡されることを期待する場合があります stdin
.
The input
キーワード引数 subprocess.run
にデータを渡すことができます stdin
サブプロセスの。 例えば:
import subprocess
import sys
result = subprocess.run(
[sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater"
)
このコードを実行すると、次のような出力が返されます。
Outputunderwater
この場合、バイトを渡しました underwater
に input
. ターゲットサブプロセスは、sys.stdinを使用して渡されたものを読み取りました stdin
(underwater
)そしてそれを私たちの出力に印刷しました。
The input
キーワード引数は、複数のチェーンを作成する場合に役立ちます subprocess.run
あるプログラムの出力を別のプログラムへの入力として渡すことを一緒に呼び出します。
結論
The subprocess
モジュールはPython標準ライブラリの強力な部分であり、外部プログラムを実行してその出力を簡単に検査できます。 このチュートリアルでは、使用方法を学びました subprocess.run
外部プログラムを制御し、入力をそれらに渡し、それらの出力を解析し、それらの戻りコードをチェックします。
The subprocess
モジュールは、このチュートリアルでは取り上げなかった追加のクラスとユーティリティを公開します。 ベースラインができたので、サブプロセスモジュールのドキュメントを使用して、他の利用可能なクラスとユーティリティについて詳しく知ることができます。