17.5. "popen2" --- アクセス可能な I/O ストリームを持つサブプロセス生成
**********************************************************************

バージョン 2.6 で非推奨: このモジュールは時代遅れです。 "subprocess"
モジュールを利用してください。特に 古い関数を subprocess モジュールで
置き換える 節を参照してください。

このモジュールにより、Unix および Windows でプロセスを起動し、その入力
／出力／エラー出力パイプに接続し、そのリターンコードを取得することがで
きます。

"subprocess" モジュールは、新しいプロセスを実行して結果を取得するため
のより強力な機能を提供しています。  "popen2" の代わりに "subprocess"
モジュールを利用することが推奨されています。

このモジュールで提供されている第一のインタフェースは 3 つのファクトリ
関数です。これらの関数のいずれも、 *bufsize* を指定した場合、 I/O パイ
プのバッファサイズを決定します。 *mode* を指定する場合、文字列 "'b'"
または "'t'" でなければなりません; Windows では、ファイルオブジェクト
をバイナリあるいはテキストモードのどちらで開くかを決めなければなりませ
ん。 *mode* の標準の値は "'t'" です。

Unix では *cmd* はシーケンスでもよく、その場合には ("os.spawnv()" のよ
うに) 引数はシェルを介在させずプログラムに直接渡されます。 *cmd* が文
字列の場合、("os.system()" のように) シェルに渡されます。

子プロセスからのリターンコードを取得するには、 "Popen3" および
"Popen4" クラスの "poll()" あるいは "wait()" メソッドを使うしかありま
せん; これらの機能は Unix でしか利用できません。この情報は "popen2()"
、 "popen3()" 、および "popen4()" 関数、あるいは "os" モジュールにおけ
る同等の関数の使用によっては得ることができません。 ("os" モジュールの
関数から返されるタプルは "popen2" モジュールの関数から返されるものとは
違う順序です。)

popen2.popen2(cmd[, bufsize[, mode]])

   *cmd* をサブプロセスとして実行します。ファイルオブジェクト
   "(child_stdout, child_stdin)" を返します。

popen2.popen3(cmd[, bufsize[, mode]])

   *cmd* をサブプロセスとして実行します。ファイルオブジェクト
   "(child_stdout, child_stdin, child_stderr)" を返します。

popen2.popen4(cmd[, bufsize[, mode]])

   *cmd* をサブプロセスとして実行します。ファイルオブジェクト
   "(child_stdout_and_stderr, child_stdin)" を返します。

   バージョン 2.0 で追加.

Unix では、ファクトリ関数によって返されるオブジェクトを定義しているク
ラスも利用することができます。これらのオブジェクトは Windows 実装で使
われていないため、そのプラットフォーム上で使うことはできません。

class popen2.Popen3(cmd[, capturestderr[, bufsize]])

   このクラスは子プロセスを表現します。通常、 "Popen3" インスタンスは
   上で述べた "popen2()" および "popen3()" ファクトリ関数を使って生成
   されます。

   "Popen3" オブジェクトを生成するためにいずれかのヘルパー関数を使って
   いないのなら、 *cmd* パラメタはサブプロセスで実行するシェルコマンド
   になります。 *capturestderr* フラグに真を与えることで、このオブジェ
   クトが子プロセスの標準エラー出力をキャプチャすべきであることを指示
   します。標準の値は偽です。 *bufsize* パラメタを指定すると、子プロセ
   スへの／からの I/O バッファサイズとして使われます。

class popen2.Popen4(cmd[, bufsize])

   "Popen3" に似ていますが、標準エラー出力を標準出力と同じファイルオブ
   ジェクトでキャプチャします。このオブジェクトは通常 "popen4()" で生
   成されます。

   バージョン 2.0 で追加.


17.5.1. Popen3 および Popen4 オブジェクト
=========================================

"Popen3" および "Popen4" クラスのインスタンスは以下のメソッドを持ちま
す:

Popen3.poll()

   子プロセスがまだ終了していない際には "-1" を、そうでない場合にはス
   テータスコード ("wait()" を参照) を返します。

Popen3.wait()

   子プロセスの状態コード出力を待機して返します。状態コードでは子プロ
   セスのリターンコードと、プロセスが "exit()" によって終了したか、あ
   るいはシグナルによって死んだかについての情報を符号化しています。状
   態コードの解釈を助けるための関数は "os" モジュールで定義されていま
   す; プロセス管理 節の "W*()" 関数ファミリを参照してください。

以下の属性も利用可能です:

Popen3.fromchild

   子プロセスからの出力を提供するファイルオブジェクトです。 "Poepn4"
   インスタンスの場合、この値は標準出力と標準エラー出力の両方を提供す
   るオブジェクトになります。

Popen3.tochild

   子プロセスへの入力を提供するファイルオブジェクトです。

Popen3.childerr

   コンストラクタに *capturestderr* を渡した際には子プロセスからの標準
   エラー出力を提供するファイルオブジェクトで、そうでない場合 "None"
   になります。 "Popen4" インスタンスでは、この値は常に "None" になり
   ます。

Popen3.pid

   子プロセスのプロセス番号です。


17.5.2. フロー制御の問題
========================

何らかの形式でプロセス間通信を利用している際には常に、制御フローについ
て注意深く考える必要があります。これはこのモジュール (あるいは "os" モ
ジュールにおける等価な機能) で生成されるファイルオブジェクトの場合にも
あてはまります。

親プロセスが子プロセスの標準出力を読み出している一方で、子プロセスが大
量のデータを標準エラー出力に書き込んでいる場合、この子プロセスから出力
を読み出そうとするとデッドロックが発生します。同様の状況は読み書きの他
の組み合わせでも生じます。本質的な要因は、一方のプロセスが別のプロセス
でブロック型の読み出しをしている際に、 "_PC_PIPE_BUF" バイトを超えるデ
ータがブロック型の入出力を行うプロセスによって書き込まれることにありま
す。

こうした状況を扱うには幾つかのやりかたがあります。

多くの場合、もっとも単純なアプリケーションに対する変更は、親プロセスで
以下のようなモデル:

   import popen2

   r, w, e = popen2.popen3('python slave.py')
   e.readlines()
   r.readlines()
   r.close()
   e.close()
   w.close()

に従うようにし、子プロセスで以下のようなコードにすることでしょう:

   import os
   import sys

   # note that each of these print statements
   # writes a single long string

   print >>sys.stderr, 400 * 'this is a test\n'
   os.close(sys.stderr.fileno())
   print >>sys.stdout, 400 * 'this is another test\n'

とりわけ、 "sys.stderr" は全てのデータを書き込んた後に閉じられなければ
ならないということに注意してください。さもなければ、 "readlines()" は
返ってきません。また、 "sys.stderr.close()" が "stderr" を閉じないよう
に "os.close()" を使わなければならないことにも注意してください。 (そう
でなく "sys.stderr" に関連付けると、暗黙のうちに閉じられてしまうので、
それ以降のエラーが出力されません)。

より一般的なアプローチをサポートする必要があるアプリケーションでは、パ
イプ経由の I/O を "select()" ループでまとめるか、個々の "popen*()" 関
数や "Popen*" クラスが提供する各々のファイルに対して、個別のスレッドを
使って読み出しを行います。

参考:

  "subprocess" モジュール
     サブプロセスの生成と管理のためのモジュール。
