\section{\module{popen2} ---
         アクセス可能な I/O ストリームを持つ子プロセス生成}

\declaremodule{standard}{popen2}
  \platform{Unix, Windows}
\modulesynopsis{アクセス可能な I/O ストリームを持つ子プロセス生成。}
\sectionauthor{Drew Csillag}{drew_csillag@geocities.com}


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

Python 2.0 から、この機能は \refmodule{os} モジュールにある
関数を使って得ることができるので注意してください。
\refmodule{os} にある関数はこのモジュールにおけるファクトリ関数
と同じ名前を持ちますが、戻り値に関する取り決めは \refmodule{os}
の関数の方がより直感的です。

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

\UNIX では\var{cmd}はシーケンスでもよく、その場合には
(\function{os.spawnv()}のように)引数はプログラムシェルを経由せず直接渡
されます。
\var{cmd}が文字列の場合、(\function{os.system()}のように)シェルに渡されます。

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

\begin{funcdesc}{popen2}{cmd\optional{, bufsize\optional{, mode}}}
\var{cmd} をサブプロセスとして実行します。ファイルオブジェクト
\code{(\var{child_stdout}, \var{child_stdin})} を返します。
\end{funcdesc}

\begin{funcdesc}{popen3}{cmd\optional{, bufsize\optional{, mode}}}
\var{cmd} をサブプロセスとして実行します。ファイルオブジェクト
\code{(\var{child_stdout}, \var{child_stdin}, \var{child_stderr})}
を返します。
\end{funcdesc}

\begin{funcdesc}{popen4}{cmd\optional{, bufsize\optional{, mode}}}
\var{cmd} をサブプロセスとして実行します。ファイルオブジェクト
\code{(\var{child_stdout_and_stderr}, \var{child_stdin})}.
\versionadded{2.0}
\end{funcdesc}


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

\begin{classdesc}{Popen3}{cmd\optional{, capturestderr\optional{, bufsize}}}
このクラスは子プロセスを表現します。通常、 \class{Popen3}
インスタンスは上で述べた \function{popen2()} および \function{popen3()} 
ファクトリ関数を使って生成されます。

\class{Popen3} オブジェクトを生成するためにいずれかのヘルパー関数を
使っていないのなら、\var{cmd} パラメタは子プロセスで実行する
シェルコマンドになります。\var{capturestderr} フラグが真であれば、
このオブジェクトが子プロセスの標準エラー出力を捕獲しなければならない
ことを意味します。標準の値は偽です。\var{bufsize} パラメタが存在
する場合、子プロセスへの／からの I/O バッファのサイズを指定します。
\end{classdesc}

\begin{classdesc}{Popen4}{cmd\optional{, bufsize}}
\class{Popen3} に似ていますが、標準エラー出力を標準出力と同じファイル
オブジェクトで捕獲します。このオブジェクトは通常 \function{popen4()} で
生成されます。
\versionadded{2.0}
\end{classdesc}


\subsection{Popen3 および Popen4 オブジェクト \label{popen3-objects}}

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

\begin{methoddesc}[Popen3]{poll}{}
子プロセスがまだ終了していない際には \code{-1} を、そうでない場合には
リターンコードを返します。
\end{methoddesc}

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


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

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

\begin{memberdesc}[Popen3]{tochild}
子プロセスへの入力を提供するファイルオブジェクトです。
\end{memberdesc}

\begin{memberdesc}[Popen3]{childerr}
コンストラクタに \var{capturestderr} を渡した際には子プロセスからの
標準エラー出力を提供するファイルオブジェクトで、そうでない場合
\code{None} になります。
\class{Popen4} インスタンスでは、この値は常に \code{None} になります。
\end{memberdesc}

\begin{memberdesc}[Popen3]{pid}
子プロセスのプロセス番号です。
\end{memberdesc}


\subsection{フロー制御の問題 \label{popen2-flow-control}}

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

% Example explanation and suggested work-arounds substantially stolen
% from Martin von Loewis:
% http://mail.python.org/pipermail/python-dev/2000-September/009460.html

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

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

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


\begin{verbatim}
import popen2

r, w, e = popen2.popen3('python slave.py')
e.readlines()
r.readlines()
r.close()
e.close()
w.close()
\end{verbatim}

に従うようにし、子プロセスで以下:

\begin{verbatim}
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'
\end{verbatim}

のようなコードにすることでしょう。

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

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




