実行に時間がかかる処理を行うなら、夜寝たりとか別作業をしたりしたい。
そうなると、いつの間にか処理が失敗しており、気づくまでの間の時間がタイムロスになったりすることが度々ある。
そこでPythonで何か異常を検知したら警告音を出してくれるような仕組みを作りたい。
それも、なるべく再利用できるような形にしておきたいのと、汎用的にしたい。
テキトーに警告音となるMP3ファイル(今回はkeikoku01shibu.mp3)を用意する。
デコレータでラッパー関数を作り、ラッパーされる処理が特定の条件を満たしたり、例外が発生したらその警告音を出すようにする。
from playsound import playsound
def watch_allert_with_args(arg = None):
def watch_allert(func):
def _watch_allert(*args, **kwargs):
path = 'sounds/keikoku01shibu.mp3'
try:
result = func(*args, *kwargs)
if (result == arg) or\
((arg is not None) and (hasattr(arg, "__iter__")) and (result in arg)):
print("警告: 条件が満たされました!result:",result)
# 警告音を再生する
playsound(path)
except Exception as e:
print("警告: 条件が満たされました!", e)
# 警告音を再生する
playsound(path)
return _watch_allert
return watch_allert
ちなみにplaysound
をインストールして普通に使おうとすると、Python3に対応していないらしく、追加でPyObjC
をインストールする必要があった。
使い方は例えば以下のようになる。
以下は二次方程式$x^2-2x+3=0$の実数解を求めるためのsample関数だが、この方程式に実数解は存在しない。
解がなかったら(つまりresult == []
のとき)警告音を出したいので@watch_allert_with_args([])
のようにして[]
を引数に持たせている。
@watch_allert_with_args([])# resultが空になったら警告を出す
def sample():
# 二次方程式x^2 -2x + 3 = 0の実数解を求める。(実数解はないため警告を出す)
x = sympy.Symbol('x', real=True)
result=sympy.solve(x**2 - 2 * x + 3)
return result
if __name__ == "__main__":
sample()
以下はまた別の例である。
この関数は、整数0で整数を割ることによる例外が発生する。
この例外を検知し警告音が鳴る。
@watch_allert_with_args()
def sample():
# 100を10から-10までの整数で割り続けて更新していく処理(0で割る時に例外が発生し警告音が出る)
sum = 100
for i in range(10,-10,-1):
sum /= i
return sum
if __name__ == "__main__":
sample()
こんな感じで、長時間実行したい関数などにラッパー関数で監視させておくことができる。
Google Colaboratoryではなぜかplaysoundが使えなかった(playsoundを使うために必要なモジュールのimportがsubprocessの問題でできなかった)ため、displayとAudioで代用した。
逆にPythonスクリプトの方でもdisplayとAudioを使って警告音を出すようにして仕組みを統一したかったが、displayとAudioはnotebookのセルでないと音が出せなかった。
(Pythonスクリプトでもnotebookでも同じように音を出すような方法はないだろうか?自分でラッパー関数を作らないといけない?)
from IPython.display import Audio, display
def watch_allert_with_args(arg = None):
def watch_allert(func):
def _watch_allert(*args, **kwargs):
path = "/content/drive/MyDrive/sounds/keikoku01shibu.mp3"
try:
result = func(*args, *kwargs)
if (result == arg) or\
((arg is not None) and (hasattr(arg, "__iter__")) and (result in arg)):
print("警告: 条件が満たされました!result:",result)
# 警告音を再生する
display(Audio(path, autoplay=True))
except Exception as e:
print("警告: 条件が満たされました!", e)
# 警告音を再生する
display(Audio(path, autoplay=True))
return _watch_allert
return watch_allert
まあこんなようにして、対象となる関数が特定の値を返したり、特定のイテラブル変数に含まれたり、例外を発生させたりする場合には警告音を出させて気付けるようにはできた。
ただしVSCodeのブレークポイントの条件文みたいな柔軟さは実現できていない。
あとは警告音を出すといっても、今はちょっとした音声でしかないので、眠りが深かったりしたら気付けないかもしれない。単純にMP3ファイルの音声を流したりするのではなく、意識的に止めない限り鳴らし続けたり、YouTubeとかから緊急地震速報の動画を流したりするのも良いかもしれない。
そこら辺はまだ課題としつつも、ひとまず当座の目的は達成できたからよしとしよう。