Pythonの標準ライブラリであるhttp.serverを使って、簡易httpサーバを立て簡単なwebアプリを作る機会があったのですが、そのとき調べた備忘録&ちょっとした説明です。
cgiを動かしてるコンソール上にprintしたい
プログラムを書いているとき、「あれ、なんかエラー起こしてる。変数の中身がなんかおかしい」となることがあると思います。自分は基本的にものぐさなので、適当にエラー前で怪しい変数をprintしたりしますが、cgi上で動くプログラムだとそうも行きません。
python内でhtml本文を作成しprintするプログラムだと、適当な場所でただprintしても表示されません。一手間加えてhtmlに変数を表示させるような場所を作ったところで、そもそもエラー起こしてたらhtmlが表示されないから意味がなかったり、ajax通信でデータを受け取り結果を返すプログラムだったとしても、同じく受け取り側でなんやかんや……と面倒臭い。
そんなとき、「とりあえず簡易的にでいいから、サーバのログを垂れ流し続けているコンソール上に表示させたい!」と思うこともあると思います。というかあった。そんなときは、以下のようにprint関数の引数fileを指定すればokです。
import sys
print('いろはにほ',file=sys.stderr)
a=[1,2,3,4]
print(a,a,a,file=sys.stderr)
いろはにほ
[1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 4]
何やってるの?
ここから先は、とりあえずやっていることの簡単な解説です。
まず、唐突に出てきたprintの引数fileから。これは、print関数の出力ファイルを指定する引数です。指定できるのは、open()の返り値であるようなファイルオブジェクトです。なので、適当なファイルを書き込み/追記モードでopenして指定すれば、printの結果をファイルに書き込むこともできます。……素直にwriteで書き込むのと何が違うんだって話ですが。
次に、sys.stderrは標準エラー出力を指しています。まあ、読んで字のごとく「特に指定がなかった場合にエラーを出力する場所」のことです。この標準出力がコンソールを指定しているため、print関数の結果がコンソールに表示されるようになったわけです。
ちなみに、デフォルトではprintの出力場所として、sys.stdoutが指定されています。これは標準出力を指定しています。通常コンソールからプログラムを実行する場合、標準出力と標準エラー出力は、どちらも同じコンソールを指しています。なので、プログラムの実行経過や結果をprintした結果も、実行中に発生した何らかのエラーも同じコンソールへと出力されます。
しかし、サーバからプログラムを実行する場合では話が変わってきます。このとき、標準出力は通信先のクライアントへの出力(webサーバへ出力->クライアント)を指しています。なので、引数を指定しないままprintしてもコンソールには表示されませんでした。それに対し、標準エラー出力はサーバを実行中のコンソール(webサーバへ出力->コンソール)を指しています。そこで出力先を標準エラー出力に変更すると、コンソールへと表示されるように変わったわけです。