Pythonのwarningsで警告(Warning)を非表示、例外化
Pythonのライブラリで廃止予定の関数を使った場合などに警告(Warning)が出力されることがある。警告を非表示にしたり、例外として扱ったりするには、標準ライブラリのwarningsモジュールを使う。
warningsモジュールには警告を発するための関数warn()
などもあるが、ここでは触れない。自作の関数などの中で警告を発したい場合は上記の公式ドキュメントを参照されたい。
本記事のサンプルコードでは以下のモジュールをインポートしている。pandas.DataFrame
はあくまでも警告の例として使うだけなので中身は気にしなくてよい。
import warnings
import pandas as pd
df = pd.DataFrame([[0, 1, 2], [3, 4, 5]])
警告(Warning)の例
リテラルのis比較によるSyntaxWarning
文字列リテラルや数値リテラルをis
で比較するとSyntaxWarning
が発せられる。
- 関連記事: Pythonの==演算子とis演算子の違い
print(100 is 100)
# True
#
# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_60077/3973932639.py:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# print(100 is 100)
pandasのSettingWithCopyWarning
pandasのchained assignmentに対してはSettingWithCopyWarning
が発せられる。
df.iloc[:1][0] = 0
# /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_60077/1345802814.py:1: SettingWithCopyWarning:
# A value is trying to be set on a copy of a slice from a DataFrame.
# Try using .loc[row_indexer,col_indexer] = value instead
#
# See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
# df.iloc[:1][0] = 0
警告を非表示
警告の扱いを変更するにはwarnings.simplefilter()
、変更した設定をデフォルトに戻す(リセットする)にはwarnings.resetwarnings()
を使う。
- warnings.simplefilter() --- 警告の制御 — Python 3.11.4 ドキュメント
- warnings.resetwarnings() --- 警告の制御 — Python 3.11.4 ドキュメント
なお、最初からすべての警告を非表示にして無視するのはおすすめしない。あくまでも警告が発生することを認識し原因を理解した上で、例えばJupyter Notebook(IPython Notebook)の出力をスッキリさせたいというような状況でのみ非表示にするべき。
すべての警告を表示させない
warnings.simplefilter()
の第一引数action
を'ignore'
とするとすべての警告が非表示になる。
warnings.simplefilter('ignore')
print(100 is 100)
# True
df.iloc[:1][0] = 0
第一引数action
には、警告を例外として扱う'error'
や警告を一度だけ発する'once'
なども指定できる。'error'
については後述。
非表示にするカテゴリを指定
warnings.simplefilter()
の第二引数category
に対象とする警告カテゴリを指定できる。FutureWarning
やDeprecationWarning
, SyntaxWarning
, RuntimeWarning
などがある。
第二引数category
のデフォルトは、すべての警告カテゴリクラスの基底クラスWarning
。上の例のように、デフォルトではすべての警告が対象となる。
警告カテゴリは警告メッセージに記述されている。上述のようにリテラルのis
による比較はSyntaxWarning
でpandasのchained assignmentはSettingWithCopyWarning
。
例えばcategory=SyntaxWarning
とすると、リテラルのis
比較の警告は非表示になるがchained assignmentによる警告は出力される。
warnings.resetwarnings()
warnings.simplefilter('ignore', SyntaxWarning)
print(100 is 100)
# True
df.iloc[:1][0] = 0
# /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_60077/1345802814.py:1: SettingWithCopyWarning:
# A value is trying to be set on a copy of a slice from a DataFrame.
# Try using .loc[row_indexer,col_indexer] = value instead
#
# See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
# df.iloc[:1][0] = 0
chained assignmentによる警告のカテゴリSettingWithCopyWarning
はpandasで独自に定義されたものなので、そのまま指定するとエラーとなる。ライブラリ内で定義されたカテゴリクラスを読み込んで指定しなければならない。
warnings.resetwarnings()
# warnings.simplefilter('ignore', SettingWithCopyWarning)
# NameError: name 'SettingWithCopyWarning' is not defined
warnings.simplefilter('ignore', pd.errors.SettingWithCopyWarning)
print(100 is 100)
# True
#
# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_60077/3973932639.py:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# print(100 is 100)
df.iloc[:1][0] = 0
警告を例外として扱う
警告が発生しても処理は止まることなく実行される。厳格に、警告でも例外のように処理を止めたいという場合は、warnings.simplefilter()
の第一引数action
を'error'
とする。
warnings.resetwarnings()
warnings.simplefilter('error')
# print(100 is 100)
# SyntaxError: "is" with a literal. Did you mean "=="?
ここでは便宜上コメントアウトしているが、実際にコードを実行すると警告が発生した時点でプログラムが途中終了する。
'ignore'
で非表示にする場合と同じく、第二引数category
で対象とする警告カテゴリを指定できる。カテゴリごとに別々のアクションを指定することも可能。
warnings.resetwarnings()
warnings.simplefilter('ignore', SyntaxWarning)
warnings.simplefilter('error', pd.errors.SettingWithCopyWarning)
print(100 is 100)
# True
# df.iloc[:1][0] = 0
# SettingWithCopyWarning: ...
一時的に警告を制御
一時的に警告を制御したい場合は、with
ブロックとwarnings.catch_warnings()
を使う。
with
ブロック内でのみwarnings.simplefilter()
による変更が有効になる。ブロックの外ではそのまま。
warnings.resetwarnings()
with warnings.catch_warnings():
warnings.simplefilter('ignore')
df.iloc[:1][0] = 0
df.iloc[:1][0] = 0
# /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_60077/1345802814.py:1: SettingWithCopyWarning:
# A value is trying to be set on a copy of a slice from a DataFrame.
# Try using .loc[row_indexer,col_indexer] = value instead
#
# See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
# df.iloc[:1][0] = 0
Python3.11から、warnings.catch_warnings()
に引数action
やcategory
が追加された。warnings.simplefilter()
の引数action
, category
に渡されたものとして扱われる。
with warnings.catch_warnings(action='ignore', category=pd.errors.SettingWithCopyWarning):
df.iloc[:1][0] = 0