はじめに
プログラムを組むにあたり、バグを出さないよう論理的にコーディングするのは当然のことだ。
とはいえ、バグがないことを断言することはできない。人間だもの。
いろいろなエラーを起こすプログラム
こんなプログラムを書いてみた。
実行するたびにさまざまなステップでエラーで停止したり最後まで完走したりするという内容だ。
import random
import math
import sys
print ("="*20)
"""
後でここに追記する
"""
p = random.randint(-3, 3)
print (f"{p}です")
if p == 3:
print (p + "の倍数だとアホになります")
elif p == -3:
print (p , "だと中断します")
exit()
elif p == -2:
print (p , "だとKeyboardInterruptが発生します")
raise KeyboardInterrupt
print ("平方根:")
print (f" sqrt({p}) = {math.sqrt(p)}")
print ("逆数:")
print (f" 1/{p} = {1/p}")
subprocess
プログラムから他プログラムを呼び出し、またその結果(標準出力)を拾うことができる。それがsubprocess
だ。MS-DOSの時代を体験していない私には標準出力やパイプは少々難解だった、がんばって勉強した。
以下の記事がたいへん役に立った。
上のmake_error.py
に以下のコードを追記しよう。追記するとこれ単品では動かなくなってしまう。それを避けるのは容易だが本題から外れるので省略している。で、できないわけじゃないからね。勘違いしないでよね。
args = sys.argv
e = sys.argv[1]
if e != "":
print (f"前回のエラー:{e}")
else:
print ("前回は正常に終了しました\n")
そして実行するのはmake_error.py
ではなく次のsubprocess_watch.py
だ。
import time
import subprocess as sp
def run_subprocess(e):
proc = sp.Popen(["python", "make_error.py", e], stdout = sp.PIPE, stderr = sp.PIPE)
return proc
proc = run_subprocess("")
while True:
ecode = proc.poll()
if ecode is None: # サブプロセスが実行中
time.sleep(2)
else: # サブプロセス終了
for line in proc.stdout.readlines():
print (line.decode(encoding="cp932"), end="") # utf-8だと全角文字でエラーになる(Windows)
if ecode == 0: # 正常終了
e = ""
else: # 異常終了
e = proc.stderr.readlines()[-1].decode()
proc = run_subprocess(e)
これによりmake_error.py
がエラーで落ちても再起動し、かつ前回のエラーメッセージを拾うことができる。
もちろん大元のsubprocess_watch.py
が落ちてしまってはダメだけど。
====================
前回は正常に終了しました
2です
平方根:
sqrt(2) = 1.4142135623730951
逆数:
1/2 = 0.5
====================
前回は正常に終了しました
-1です
平方根:
====================
前回のエラー:ValueError: math domain error
-3です
-3 だと中断します
====================
前回は正常に終了しました
-2です
-2 だとKeyboardInterruptが発生します
====================
前回のエラー:KeyboardInterrupt
1です
平方根:
sqrt(1) = 1.0
逆数:
1/1 = 1.0
まともな使い方
以上のことを家族見守りサービスを自作するの開発中に習得した。
それにより不慮のエラーが発生しても再起動することができるようになった。
どのようなエラーが発生したかわかるようになったのならば分析して修正しろって? ごもっともです。
終わりに
今回はPythonプログラムの再起動に使っただけだが、用途はそれだけに限らない。Pythonでできないことを外に出し、その結果をもらってPythonで処理するという利用法もある。