warnings - Warning control#
Warnings 是 Python 中负责警告的模块. 它通常是发出一些警告信息, 但不会阻止程序运行.
[3]:
import warnings
Define Custom Warning#
[13]:
class MyWarning(Warning):
pass
Raise Warning#
[16]:
def my_func():
warnings.warn("My warning in my_func()!", MyWarning)
print("run my_func()")
[18]:
print("before")
my_func()
print("after")
before
run my_func()
after
/var/folders/3y/7t5ll4sn6x76g8rhfqlc36dw0000gn/T/ipykernel_58584/1986793376.py:2: MyWarning: My warning in my_func()!
warnings.warn("My warning in my_func()!", MyWarning)
Temporarily Suppressing Warnings#
有的时候你知道一段代码会抛出 warning, 而且你很清楚这个 warning 是可以被忽略的, 你不希望打印出 warning 信息. 但是你又不希望因为禁用了全部的 warning 导致在这一段代码外应该抛出 warning 的地方没有抛出. 你希望用类似 try ... except ExpectedException
这样的方式不仅精确控制忽略 warning 的代码块, 并且还能清晰的指定只忽略特定 的 warning 类型.
warning 模块提供了两个 API 可以做到这一点:
warnings.catch_warnings: 它是一个 context manager, 能够暂时的修改全局的 warning 的设置并在推出 context 后自动恢复原有设置.
warnings.simplefilter: 它是一个函数, 能修改全局的 warning filter 的设置. 其中它有两个关键参数,
action
和category
.action
定义了 match 到特定 warning 后应该怎么处理 (请参考 Warning Filter), 例如有: “ignore” 表示不打印 warning, “error” 表示将其转化为 Exception. 等等. 而category
则定义了要过滤的 warning 类. 所有指定类的子类都会被过滤掉. 这根 try, except 机制一样. 其中Warning
是所有 warning 类的基类.
值得注意的是在 3.11 中 catch_warnings
加入了 action
, category
参数. 也就是说 3.11 之前你需要两个 API 配合使用, 而 3.11 后则只需要 catch_warnings
即可.
Reference:
You won’t see the warning.
[21]:
with warnings.catch_warnings():
# ignore it
warnings.simplefilter("ignore", MyWarning)
my_func()
run my_func()
Without context manager, you still see the warning.
[22]:
my_func()
run my_func()
/var/folders/3y/7t5ll4sn6x76g8rhfqlc36dw0000gn/T/ipykernel_58584/1986793376.py:2: MyWarning: My warning in my_func()!
warnings.warn("My warning in my_func()!", MyWarning)
You still see the warning, because the category is wrong.
[23]:
with warnings.catch_warnings():
# wrong Warning type
warnings.simplefilter("ignore", category=DeprecationWarning)
my_func()
run my_func()
/var/folders/3y/7t5ll4sn6x76g8rhfqlc36dw0000gn/T/ipykernel_58584/1986793376.py:2: MyWarning: My warning in my_func()!
warnings.warn("My warning in my_func()!", MyWarning)
Testing Warnings#
有的时候你需要测试你的代码, 看看 warning 是不是真的被抛出了. 在 pytest 框架中有一个 with pytest.raises(YourException)
的 API 可以做到测试指定异常是不是被抛出了. 类似地, warnings.catch_warnings 也能做到这一点.
Reference:
[24]:
with warnings.catch_warnings(record=True) as w:
# Cause all warnings always to be triggered.
warnings.simplefilter("always", category=MyWarning)
# Trigger a warning.
my_func()
# Verify some things
assert len(w) == 1
run my_func()
[ ]: