Python で標準出力をリアルタイムに出力する方法

Jenkinsで実行ログをリアルタイムで確認したい

Jenkis ではジョブの実行ログをリアルタイムに確認することができる。
しかし、 ( Python ではスクリプト言語のため)、処理を高速化するために標準出力をバッファしてまとめて出力する。
なので、 Jenkins でジョブの動作を確認する場合、まとまった単位で標準出力のログが出力される。
毎日、定時に実行するようば定例バッチの場合はそれでもいいが、
開発途中の場合、リアルタイムにログがみたい場合があると思う。
そのような場合の忘備録を残す。

Pythonでリアルタイムに標準出力するには

Pythonでは使うバージョンによって、即時標準出力する方法が異なる。

Python3.3以降

これは有名な方法だが、 flush オプションを True で設定する。

print("プリントする文言", flush=True)

Python3.3より前 + Python2.X 系

2020年には Python 2系はメンテされなくなると思うが、一応載せておく。
sys.stdout.flush() を使うことで flush される。

import sys
print("プリントする文言")
# Python 2系なら
# print "プリントする文言"
sys.stdout.flush()

いちいち仕込むべきなのか

冒頭で書いたように、バッチの性質によって必ずしも常に flush する必要はないと思う。
しかし、リアルタイムに出力させたい場合に備えて、 flush を仕込む方針を取ると非常に厄介だと思う。
例えば、今ブログを書きながらで思いつく方法としては、
バッチ実行時に flush をするかどうかの判定を挟む方法だ。
例えば、環境変数に flush_flg を仕込んでそれを使って判定する、のような処理。
この場合、個人で開発している場合は統一できるかもしれないが、時間の経過と共に忘れてしまったりするし、 チームで開発している場合、人それぞれの書き方や基準があやふやになって推奨できない。 また、そのために共通関数化するのもたかが標準出力のためにバカらしい。 不用意な変数を仕込むのでバグの温床にもなりかねない。 なので、できるならシンプルな形式に留めるほうが良いと思う。

Python のオプションを使う

Python のオプションに -u オプションがある。
python -h とすると用途が見られる。 以下に出力を抜粋する。
ちなみに自分が使っているバージョンは Anaconda の Python 3.6.5 である。

$ python -V
Python 3.6.5 :: Anaconda, Inc.

$ python -h
... (抜粋)
-u     : force the binary I/O layers of stdout and stderr to be unbuffered;
         stdin is always buffered; text I/O layer will be line-buffered;
         also PYTHONUNBUFFERED=x
...

とある。
要約すると、標準出力とエラー出力を強制的にバッファしないようにする。とのこと。
つまり、このオプションを使えば flush と同じことができる。
なので、例えば開発環境などで随時標準出力を見たい場合は、 Jenkins のジョブ実行スクリプト画面で

python -u <実行するスクリプト>

すればよいし、そのまま定例実行に切り替えるときは、

python <実行するスクリプト>

とするだけでよい。

FYI

Python2 count down

https://pythonclock.org/