获取警告的追踪信息
在numpy中,我们可以使用 np.seterr(invalid='raise')
这个命令,让警告变成错误,这样就能看到具体的错误信息和出错的位置(可以参考 这篇文章)。
- 有没有什么通用的方法可以追踪警告信息呢?
- 我能不能让python在出现警告时也给出错误的详细信息?
5 个回答
记录警告的选项,尽量不打断程序的运行。
获取错误追踪信息,但不抛出错误:
import warnings
import traceback
warnings.filterwarnings("error") # Treat warnings as errors
try:
your_code()
except Warning:
print(traceback.format_exc()) # print traceback
warnings.resetwarnings() # Back to default behavior
如果你想无论如何都执行相同(或类似)的代码,可以把它放在except
块里,这次可以忽略警告,因为你已经得到了它的追踪信息:
import warnings
import traceback
warnings.filterwarnings("error") # Treat warnings as errors
try:
your_code()
except Warning:
print(traceback.format_exc()) # print traceback
warnings.filterwarnings("ignore") # ignore warnings
your_code() # Execute either way (same code or alternative code)
warnings.resetwarnings() # Back to default behavior
对于Python3,可以查看warnings模块文档中的stacklevel
参数。当第三方库的警告信息被隐藏在调用堆栈中时,这个参数特别有用:你可以把调用warnings.warn
时的参数设置为stacklevel=2
,这样就能看到错误追踪信息,根据需要进行修改,然后再把stacklevel
恢复到原来的状态。
例如:
warnings.warn("It's dangerous to go alone! Take this.", stacklevel=2)
你可以使用 warnings.filterwarnings()
这个功能,把特定的警告变成错误,这样你就能看到详细的错误信息和调用栈。下面是一个简单的示例:
import warnings
warnings.filterwarnings(
action='error', message='',
category=RuntimeWarning
)
在我的情况下:
import warnings
warnings.filterwarnings(
'error', 'DateTimeField .* received a naive datetime',
RuntimeWarning, 'django.db.models.fields'
)
你可以通过给 warnings.showwarning
赋值来实现你想要的效果。实际上,警告模块的文档 也建议你这么做,所以这并不是走上了什么“黑暗的源代码”之路。 :)
你可以通过给
warnings.showwarning
赋值来替换这个函数,使用一个不同的实现。
你可以定义一个新的函数,它的功能和 warnings.showwarning
一样,但还会打印出调用栈。然后把这个新函数放到原来的位置:
import traceback
import warnings
import sys
def warn_with_traceback(message, category, filename, lineno, file=None, line=None):
log = file if hasattr(file,'write') else sys.stderr
traceback.print_stack(file=log)
log.write(warnings.formatwarning(message, category, filename, lineno, line))
warnings.showwarning = warn_with_traceback
这样一来,每次出现警告时,都会打印出调用栈和警告信息。不过要注意,如果这个警告被忽略了(因为它不是第一次出现),那么就不会有任何反应,所以你仍然需要执行:
warnings.simplefilter("always")
你可以通过 warnings
模块的过滤器获得类似于 numpy.seterr
的控制效果。
如果你希望 Python 每次触发警告时都报告,而不仅仅是第一次,可以加入类似这样的代码:
import warnings
warnings.simplefilter("always")
你可以通过传递不同的字符串作为参数来获得其他行为。使用同一个函数,你还可以根据引发警告的模块、提供的消息、警告的类别、导致警告的代码行等等,指定不同的行为。
你可以在 模块文档 中查看相关列表。
举个例子,你可以设置所有的警告都抛出异常,除了 DeprecationWarnings
,这些应该完全忽略:
import warnings
warnings.simplefilter("error")
warnings.simplefilter("ignore", DeprecationWarning)
这样你就能在每次抛出警告时获得完整的错误追踪(只有第一次会停止执行... 但你可以逐个处理这些警告,并创建一个过滤器来忽略你不想再听到的警告...)