# 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` モジュール

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