如何完全重置警告

时间:2015-05-27 17:36:31

标签: python pandas warnings

如何在不重新启动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()时发出警告。 但是,现在如果del __warningregistry__我可以再次看到警告。

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

2 个答案:

答案 0 :(得分:3)

  

如何在不重新启动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更改为divide

接下来,我们将更改warnings模块始终显示警告的方式。我们通过设置warning filter来完成此操作。

  

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

报告此问题的bug report中描述了这一点:

  

如果您在使用简单过滤器之前没有提出警告,请执行此操作   本来会有用的。不良行为是因为   __warningsregistry__。它是第一次发出警告时设置的。   当第二个警告到来时,过滤器甚至都没有看到。   我认为解决此问题的最佳方法是使__warningsregistry__无效   何时使用过滤器。存储警告数据可能是最好的   在全局中而不是在模块上,因此很容易失效。

顺便提一下,bug已针对版本3.4和3.5进行了修复。

答案 1 :(得分:0)

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“忘记”您之前看到的警告时,可以使用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