Python: popen2を用いた子プロセスの生成方法(Popen3/4, popen3/4メソッドの違いについて)

2010年2月14日

Pythonプログラム中から他のプログラムを実行する際最も簡単な方法は、


 

 import os  os.system("ls")


上記例のように、 os.system(cmd) を使用することです。


これは、os.system(cmd)を実行している親プロセスが子プロセスを同期実行(cmdによって実行 されたプロセスが終了するまで親プロセスも停止)することで実現しているのですが、 

これでは、非同期実行もできませんし、cmdで実行された子プロセスの結果(標準出力、標準エラー出力) も取得できません。

そんなときに使うとよいのが popen2 クラスです。

popen2クラスの仕様については、 pythonライブラリヘルプ (popen2) をご覧ください。

今回は子プロセスの出力の受け取り方について説明したいと思います。

まず、popen2.popen3(cmd[, bufsize[, mode]]), popen2.popen4(cmd[, bufsize[, mode]])の違いについてですが、 これらは前者が子プロセスの標準出力と標準入力((stdout, stdin)のタプル)を返すメソッドで、 後者が子プロセスの標準出力、標準入力、標準エラー出力((stdout, stdin, stderr)のタプル)を返すメソッドです。 


つまり、エラー出力を個別に取得したい場合はpopen2.popen4()、その必要がない場合はpopen2.popen3()を用いるという 風に使い分けたら良いでしょう。

また、これら小文字で始まるpopen3/4メソッドは同期実行型で、子プロセスcmdが完了するまで親プロセスは一切 介入できません。


そこで、同期・非同期実行を細かく制御するために大文字のpopen2.Popen3/4クラスが存在します。 これらの仕様はそれぞれPopen3(cmd[, capturestderr[, bufsize]]), Popen4(cmd[, bufsize]) となっています。


これらの大きな違いは、小文字のpopen3/4とほぼ同じです。つまり、標準エラー出力を含むものがPopen4、 含まないものがPopen3という訳です。具体的に、子プロセスの結果の取得方法を以下で見てみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import popen2
cmd = "cat hoge.txt"
cp = popen2.Popen3(cmd)
cp.tochild.close()
child_stdout_fp = cp.fromchild
ret = cp.wait()
if ( ret == 0 ):
    print child_stdout_fp.read()
else:
    print "error is occurrd..."
上記は、Popen3の具体例です。


Popen3()の実行で返ってくるのは、子プロセスへアクセスするためのインスタンス(cp)です。 


このインスタンスを介してchild_process.tochild.write()などとして、子プロセスの標準入力に コマンドの引数情報を渡したり、cp.fromchildにて子プロセスの標準出力のファイルポインタを取得 することができます。


また、cp.wait()にて子プロセスの実行完了を待つこともできますし(同期処理)、wait()で待たずに 非同期処理をすることもできます。

Popen4()については、上記例のPopen3の部分をそっくりそのまま入れ替えるだけで済みます。 


そうすることで、cp.fromchildにて標準エラー出力と標準出力を両方一緒に 読み取ることができます。


popen2モジュールの使い方を良く理解すれば、かなり複雑なPythonプログラムを組めるようになりますので、 是非チャレンジしてみましょう!