サブロウ丸

サブロウ丸

主にプログラミングと数学

python, warning デバッグ

pythonでwarningをデバッグする際にpdbソースコードデバッガでcatchしてくれると、とても便利ですよね。 例えば下記のコードを実行すると

import numpy as np
x = np.ones((2, 2), dtype=np.float16)
x[0, 0] = 1e4
y = x ** 2

$ python tmp.py
/Users/tateiwa/nlp/src/tmp.py:5: RuntimeWarning: overflow encountered in square
y = x ** 2

というwarningが表示されます。 (本筋ではないですが、この場合はnp.float16で定義されたnumpy array xを2乗することで[0,0]成分がその有効範囲を超えてしまうことが原因です)

このwarningをcatchする方法を2通り紹介します。

方法1: -W error オプション

pythonのオプションとして、-W errorオプションとともにpdbを実行すると、warningをexceptionとしてcatchされます。 これは実行時のオプションを変えるだけなので、楽ですね。

$ python -W error -m pdb -c "c" tmp.py
Traceback (most recent call last):
  File "/usr/local/Cellar/python@3.9/3.9.12/Frameworks/Python.framework/Versions/3.9/lib/python3.9/pdb.py", line 1726, in main
    pdb.runscript(mainpyfile)
  File "/usr/local/Cellar/python@3.9/3.9.12/Frameworks/Python.framework/Versions/3.9/lib/python3.9/pdb.py", line 1586, in runscript
    self.run(statement)
  File "/usr/local/Cellar/python@3.9/3.9.12/Frameworks/Python.framework/Versions/3.9/lib/python3.9/bdb.py", line 580, in run
    exec(cmd, globals, locals)
  File "<string>", line 1, in <module>
  File "/Users/tateiwa/nlp/src/tmp.py", line 1, in <module>
    import numpy as np
RuntimeWarning: overflow encountered in square
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> /hogehoge/tmp.py(1)<module>()
-> import numpy as np
(Pdb) l
  1  ->   import numpy as np
  2
  3    x = np.ones((2, 2), dtype=np.float16)
  4    x[0, 0] = 1e4
  5  >>    y = x ** 2
  6  
[EOF]

ちなみに-W errorオプションをつけないと、下記のようにサラッと流れてしまいます。

python -m pdb -c "c" tmp.py
/Users/tateiwa/nlp/src/tmp.py:1: RuntimeWarning: overflow encountered in square
  import numpy as np
The program finished and will be restarted
> /Users/tateiwa/nlp/src/tmp.py(1)<module>()
-> import numpy as np

このオプションは https://docs.python.org/ja/3/using/cmdline.html#cmdoption-W にあるように、warningに関する実行時のオプションです。

方法2: warnings.filterwarnings

こちらはソースコードを変更する方法です。

import numpy as np

x = np.ones((2, 2), dtype=np.float16) x[0, 0] = 1e4

import warnings with warnings.catch_warnings(): warnings.filterwarnings('error') try: y = x ** 2 except Warning as e: raise Exception(e)

実行すると、

$ python tmp.py
Traceback (most recent call last): File "/Users/tateiwa/nlp/src/tmp.py", line 11, in <module> y = x ** 2 RuntimeWarning: overflow encountered in square

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/Users/tateiwa/nlp/src/tmp.py", line 13, in <module> raise Exception(e) Exception: overflow encountered in square

とちゃんとcatchしてくれていますね。 ちなみに, warnings.filterwarningsの引数を変えることで、catchする範囲を変更することができます。

参考: warnings --- 警告の制御 — Python 3.10.4 ドキュメント