集計結果のJSONへ「処理を開始しました」という一行が混ざると、次の道具で読めなくなります。人に見せる説明と、機械へ渡す結果を同じprintで出している場合に起こる問題です。
Pythonの標準出力stdoutと標準エラー出力stderrは分けて使えます。stdoutには決めた形式の結果、stderrには診断を出すと、次の処理へ結果を渡しやすくなります。
結果を一件のJSONとして返す
次は引数の整数を足す小さな例です。引数を省略すると架空の10と20を使います。整数へ変換できない場合はstderrへ理由を出し、終了コード2で終わります。
import json
import sys
def main():
inputs = sys.argv[1:] or ["10", "20"]
try:
values = [int(value) for value in inputs]
except ValueError:
print("整数にできない入力があります", file=sys.stderr)
return 2
result = {"count": len(values), "total": sum(values)}
print(json.dumps(result, ensure_ascii=False))
print(f"処理件数: {len(values)}", file=sys.stderr)
return 0
if __name__ == "__main__":
raise SystemExit(main())
引数なしのstdoutは、countが2、totalが30のJSON一件です。stderrには処理件数が出ます。端末では二つの出力が続けて見える場合がありますが、別の出力先です。
Windows・Python 3.12.10で、出力を分けて受け取る形で確認しました。badを引数にした場合は終了コード2でstdoutが空になること、0と5なら合計5のJSONになることも確認しています。
診断が出たことと失敗を分ける
stderrという名前でも、正常時の進捗や確認用の情報を出せます。この例は成功時にも処理件数をstderrへ書いています。stderrに文字があったという理由だけで、ジョブを失敗と判定する設計にはしません。
成否は終了コード、結果の形式、必要な出力の確認を合わせます。0以外の具体的な意味はツールごとに定義し、READMEへ残します。エラーを表示しても0で終了する構成では、呼び出し側が失敗に気づけない場合があります。
結果の前後に説明を足さない
stdoutを機械向けに決めたら、デバッグ用のprintも混ぜないようにします。成功の一言や区切り線だけでも、JSONとして読む後段では余計な文字になります。
利用者向けの詳しい案内を出すモードが必要なら、機械用の出力モードと分ける方法があります。必要な結果の形式を決めず、受け取る側で先頭や末尾の説明を削る対応を重ねると、変更に弱くなります。
保存先の文字コードも確認する
シェルでファイルへ出力する場合は、保存方法やシェルのバージョンによって文字コードが変わることがあります。Pythonの出力が分かれたことだけで、保存したファイルを後段が同じ文字コードで読めるとは判断しません。
実際に使う起動方法でstdoutとstderrを別々に保存し、結果をJSONとして読み直してください。ログへ入力の全文や秘密を出す必要があるかも分けて判断します。この例は架空の整数と件数だけを表示しています。
引数の設計はargparse入門、継続して残す診断はlogging入門で補えます。
参考資料
Python sys公式資料を2026年11月1日に確認しました。
