如何完全重置警告

How to reset warnings completely

如何在不重新启动的情况下再次看到警告python。现在我只见过他们一次。

例如考虑这段代码:

import pandas as pd  
pd.Series([1]) / 0

我明白了

RuntimeWarning: divide by zero encountered in true_divide 

但是当我再次 运行 它时,它会静默执行。

如何在不重启的情况下再次看到警告python?


我试过了

del __warningregistry__

但这无济于事。

似乎只有某些类型的警告存储在那里。 例如,如果我这样做:

def f():   
    X = pd.DataFrame(dict(a=[1,2,3],b=[4,5,6]))
    Y = X.iloc[:2]
    Y['c'] = 8

那么这只会在第一次调用 f() 时引发警告。 但是,现在 if do del __warningregistry__ 我可以再次看到警告。


第一次警告和第二次警告有什么区别?为什么这个__warningregistry__里面只存了第二个?第一个存储在哪里?

How can I see the warning again without restarting python?

只要在脚本开头执行以下操作,就不需要重新启动。

import pandas as pd
import numpy as np
import warnings
np.seterr(all='warn')
warnings.simplefilter("always")

此时每次尝试除以零时,都会显示

RuntimeWarning: divide by zero encountered in true_divide 

解释:

我们正在设置几个警告过滤器。第一个 (np.seterr) 告诉 NumPy 它应该如何处理警告。我已将其设置为在 all 上显示警告,但如果您只想查看除零警告,请将参数从 all 更改为 divide

接下来我们更改我们希望 warnings 模块始终显示警告的方式。我们通过设置 warning filter.

来做到这一点

What is the difference between first and second warning? Why only the second one is stored in this __warningregistry__? Where is the first one stored?

bug report 报告此问题时对此进行了描述:

If you didn't raise the warning before using the simple filter, this would have worked. The undesired behavior is because of __warningsregistry__. It is set the first time the warning is emitted. When the second warning comes through, the filter isn't even looked at. I think the best way to fix this is to invalidate __warningsregistry__ when a filter is used. It would probably be best to store warnings data in a global then instead of on the module, so it is easy to invalidate.

顺便说一下,bug 已经关闭,因为 3.4 和 3.5 版本已修复。

warnings 是一个非常棒的标准库模块。你会喜欢了解它的:)

一点背景知识

warnings 的默认行为是仅在第一次出现时显示来自特定行的特定警告。例如,以下代码将导致向用户显示两个警告:

import numpy as np

# 10 warnings, but only the first copy will be shown
for i in range(10):
    np.true_divide(1, 0)

# This is on a separate line from the other "copies", so its warning will show
np.true_divide(1, 0)

您有几个选项可以更改此行为。

选项 1:重置警告注册表

当你想要python到"forget"之前看到的警告时,你可以使用resetwarnings:

# warns every time, because the warnings registry has been reset
for i in range(10):
    warnings.resetwarnings()
    np.true_divide(1, 0)

请注意,这还会重置您所做的任何警告配置更改。这让我想到...

选项 2:更改警告配置

warnings module documentation 更详细地介绍了这一点,但一个直接的选择就是使用 simplefilter 来更改默认行为。

import warnings
import numpy as np

# Show all warnings
warnings.simplefilter('always')
for i in range(10):
    # Now this will warn every loop
    np.true_divide(1, 0)

由于这是全局配置更改,它具有您可能希望避免的全局影响(应用程序中任何位置的所有警告每次都会显示)。一个不那么激进的选择是使用上下文管理器:

with warnings.catch_warnings():
    warnings.simplefilter('always')
    for i in range(10):
        # This will warn every loop
        np.true_divide(1, 0)

# Back to normal behavior: only warn once
for i in range(10):
    np.true_divide(1, 0)

还有更精细的选项可用于更改特定类型警告的配置。为此,请查看 docs.