百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

在Python中处理警告(python关闭警告)

bigegpt 2024-08-02 10:43 4 浏览

我们每个人都会遇到这种情况: 你写了一些Python代码,但是你遇到了一个错误:

这不仅仅是一个错误,而是一个异常。这是Python以明确的方式表述存在问题的方式,这样,我们就可以用“try”和“except”关键字来捕获它。

就像Python中的其他东西一样,异常也是一个对象。这意味着一个异常有一个类——我们就是用这个类来捕获异常的:

我们甚至可以有几个“except”子句,每个子句会寻找一种不同类型的错误。但是,每个Python类(除了“object”)都继承自其他类,对于异常类也是如此。因此,如果我们想同时捕获“KeyError”和“IndexError”,那么我们可以显式地命名它们。或者我们可以只捕获“LookupError”,它是“KeyError”和“IndexError”的父类。

在Python标准库文档中,你可以在https://docs.python.org/3/library/exceptions.html 中查看Python的异常类层次结构。它有助于你了解Python中存在哪些异常,层次结构如何,以及一般地理解异常如何工作。

但是,如果你查看该层次结构的底部,你将看到一个名为“Warning”的异常类,以及一些子类,比如“DeprecationWarning”和“BytesWarning”。这些是什么?虽然它们与异常层次结构一起被包含在其中,警告也是异常,但它们既不会像正常的异常那样被抛出,也不会像正常的异常那样被使用。它们是什么,我们要如何使用它们?

首先,回顾一下历史: Warnings在Python中已经存在很长时间了,从Python 2.1开始(追溯到2000年)。PEP 230是由Guido van Rossum (Python的创造者和长期的“仁慈的生活的独裁者”)编写的,它的添加不仅是为了创建一种机制来提醒用户可能出现的问题,而且是为了从程序内部发送此类警告并决定如何处理它们。

为什么要用警告?

在我向你展示如何在你自己的代码中使用警告之前,让我们首先考虑一下为什么以及何时需要使用警告。毕竟,你总是可以使用“print”来显示警告。或者,如果确实有问题,那么你也可以抛出一个异常。

但这正是问题的关键:在某些时候,你想要吸引用户的注意,但又不需要停止程序或强制执行try-except子句。虽然“print”总是很有用,但它通常会写入标准输出(也就是Python中的“sys.stdout”),这意味着你的警告可能会与系统的警告本身混合在一起。

(虽然我刚写过,你可能会想要引起用户的注意,但我认为,大多数情况下,警告是针对开发人员而不是用户的。Python中的警告有点像汽车上的“所需的服务”灯;用户可能知道有些地方出了问题,但是只有一个经过认证的维修人员才会知道该怎么做。开发人员应该避免向最终用户显示警告。)

你还可以想象这样一种情况,在这种情况下,某些警告比其他警告更重要。你当然可以设计一种方案,在该方案中,程序会“print”警告,并且该警告的第一个字符将指示警告的严重程度……但是,在Python有一个完整的对象系统,以及可以自由使用的复杂数据类型的情况下,我们为什么要这样做呢?

此外,在某些情况下,用户可能不希望忽略警告。也许我在生产环境中运行的是一种非常敏感的程序,我宁愿让程序提前退出,也不愿在一个潜在的不确定情况下继续运行。

Python的警告系统考虑到了这一切:

  • 它将警告看作一个单独的输出类型 , 这样我们就不会将它与异常或者程序的打印文本相混淆。

  • 它允许我们指明我们正在发送给用户哪种警告,

  • 它可以让用户指示如何处理不同类型的警告,让一些引发严重错误,其他的在屏幕上显示它们的信息,还有一些始终被忽略,

  • 它可以让程序员开发它们自己的、新的警告类型。

并不是每个程序都需要有或使用警告。但是你的程序可能会因为加载模块或调用函数的方式而责骂用户,因此,Python的警告系统就为你提供了你想要的功能。

警告用户

假设你想要警告用户某些事情。你可以通过导入“warnings”模块来实现这一点,然后使用“warnings.warn”来告诉他们出现了什么问题:

当我运行上面的代码(在一个名为“warnings1.py”的文件中)时,会发生什么呢?输出如下:

换句话说,上面的内容都被写到了我的终端屏幕上。这三行代码都是按顺序打印的,所以警告并不是在程序的单独阶段(例如,编译)被打印的。但是在“print”语句的文本和我从警告中得到的输出之间有一个明显的区别。

首先,我们被告知警告发生在哪个文件中,在哪一行。在这样一个小而琐碎的例子中,这似乎有些过分。但是,如果你有一个包含许多不同文件的大型应用程序,那么知道是什么代码生成了警告无疑是很好的。

我们还被告知这是一个“UserWarning”—我们可以生成的警告类型之一。正如不同类型的异常允许我们选择性地捕获它们一样,不同类型的警告也允许我们以不同的方式处理它们。

但是在这个输出中还有一些隐藏的东西:“print”语句和我的“warnings.warn”语句实际上将它们的输出发送到了两个不同的地方。正如我上面写的,“print”通常会写到“标准输出”,也就是“sys.stdout”,它通常会连接到用户的终端窗口。但“warnings.warn”通常会写到“标准错误”,也就是“sys.stderr”。问题是,在默认情况下,“sys.stdout” 和 “sys.stderr”都会写到同一个地方,即用户的终端。

但是如果我把程序输出重定向到一个文件中,我们来看看会发生什么:

我告诉我的Unix shell我想运行“warnings1.py”,所有的输出都应该被放在“output.txt”中,而不是显示在屏幕上。但我并没有说“全部输出”。相反,通过使用“>”,我只重定向了发送到“sys.stdout”的输出。被发送到“sys.stderr”的警告仍然被显示出来了。这通常被认为是一件好事,它可以确保即使你将输出重定向到一个文件,你仍然能够看到警告和其他错误。因此,尽管sys.stdout 和 sys.stderr 在默认情况下都会去同一个目的地,但我们也可以看到将它们分开的好处。

不同类型的警告

假设我正在维护一个已经存在了一段时间的库。这个库有一个有用的函数,但是这个函数有点过时了,并且不支持现代的用例。作为该库的维护者,支持该函数的两个版本(旧版本和新版本)对我来说是一件痛苦的事情。

我可以在文档和社交媒体中声明,我的库的新版本(3.0)将于明年释出,而且这个新版本将不再支持该函数的旧版本。但是我们都知道程序员并不倾向于阅读文档。因此,我更愿意让用户感到震惊,告诉他们虽然旧的函数版本仍然可以运行,但他们应该开始转向更新的版本。

我该怎么做呢?当然是使用警告!下面是一个例子:

现在,只要用户运行了“hello”函数,他们就会得到一个警告。此外,因为这个警告会写到标准错误(而不是标准输出),所以它不会与正常输出混在一起。下面是来自上面代码的输出:

但还有比这更好的方法:或许我们想把普通的、乏味的警告与其他类型的警告区分开来。例如,我们可能有许多被废弃的函数。为了处理这中情况,“warnings.warn”函数支持可选的第二个参数——警告的类别。例如,我们可以使用DeprecationWarning:

我们不必“import”DeprecationWarning或任何其他的标准警告类型,因为它们已经被自动导入到了Python程序始终可用的“内置”命名空间中。这样一来,就有许多这样的警告类可以供我们使用,包括UserWarning(默认)、DeprecationWarning(我们在这里使用了)、SyntaxWarning和UnicodeWarning。你可以使用其中你认为最合适的一个。

你可能已经注意到,这些警告类别与我们在前面查看Python的内置异常层次结构时所看到的类完全相同。实际上,这些类就是这样被使用的,作为第二个参数传递给“warnings.warn”。

简单的过滤

假设你正在使用一堆旧函数,每一个函数都会提醒你,你应该切换到它们的新的替代版本。如果每次运行程序时都收到一堆警告,你可能会有点恼火。警告是用来通知你你应该进行升级……但是有时候,这些警告与其说有用,不如说是烦人。

在这种情况下,你可能希望过滤掉一些警告。现在,“filtering”是警告系统使用的一个非常普遍的术语。它基本上是让你说,“当一个匹配特定条件的警告触发时,使用它做X”——X可以是各种各样的事情。

最简单的过滤器是“warnings.simplefilter”,而调用它的最简单方法是使用单个字符串参数。这个参数告诉警告系统,如果它遇到一个警告,该怎么做:

  • “默认”——在警告第一次出现时显示它

  • “错误”——将警告转换成一个异常

  • “忽略”——忽略警告

  • “总是”——总是显示警告,即使它以前被显示过

  • “模块”——每个模块显示一次警告

  • “一次”——在整个程序中只显示一次警告

例如,如果我想忽略所有警告,我可以这样写:

并且如果我有这样的代码:

我们会看到这样的输出:

如你所见,由于使用了“ignore”,警告完全消失了。

如果我们采取另一种极端,即将警告转换为异常,会发生什么?

果然,我们得到了一个异常:

正如你所看到的,我们得到了一个UserWarning异常。我们可以在这些警告上面使用“try”和“except”,如果我们想的话,我们就可以捕获它们……尽管我必须承认,在我看来,将警告转换成异常只是为了捕获它们是很奇怪的。(不过,我相信有这样的用例。)

更具体的过滤

我提到过“simplefilter”采用了一个强制性的参数,并且我们已经看到了这些参数可以是什么。但事实证明,“simplefilter”使用了几个额外的、可选的参数,这些参数可用于指定一个警告被发出时将发生什么。

例如,假设我想忽略UserWarning,并将DeprecationWarning转换为异常。我可以这样写:

这段代码会生成以下输出:

换句话说,我们成功地忽略了一种类型的警告,同时将另一种类型的警告转换为异常——与所有异常一样,如果忽略这种异常,它将是致命的。

“simplefilter”函数接受四个参数,除了第一个参数外,其他参数都是可选的

你还能做什么?

警告系统可以处理非常广泛的各种情况,并且可以通过多种方式进行配置。除此之外,你还可以:

  • 使用-W标志从命令行定义警告过滤器

  • 设置多个过滤器,每个过滤器处理一种不同的情况

  • 指定应该过滤的消息和模块,可以以一个字符串,也可以以一个正则表达式

  • 创建你自己的警告,作为现有警告类的子类

  • 使用Python的日志模块捕获警告,而不是将输出打印到sys.stderr。

  • 将输出传递到一个你选择的可调用对象(即函数或类),而不是sys.stderr,用于更高级的处理。

  • 关于警告的原始文档(PEP 230)是一个很好的起点,它还描述了引入警告的动机。

  • 标准库中的“warnings”模块文档描述了我在这里所写的所有内容,以及更多的内容。

  • “本周Python模块”网站有一个很好的介绍:https://pymotw.com/3/warnings/


英文原文:https://lerner.co.il/2020/04/27/working-with-warnings-in-python/
译者:天天向上

相关推荐

得物可观测平台架构升级:基于GreptimeDB的全新监控体系实践

一、摘要在前端可观测分析场景中,需要实时观测并处理多地、多环境的运行情况,以保障Web应用和移动端的可用性与性能。传统方案往往依赖代理Agent→消息队列→流计算引擎→OLAP存储...

warm-flow新春版:网关直连和流程图重构

本期主要解决了网关直连和流程图重构,可以自此之后可支持各种复杂的网关混合、多网关直连使用。-新增Ruoyi-Vue-Plus优秀开源集成案例更新日志[feat]导入、导出和保存等新增json格式支持...

扣子空间体验报告

在数字化时代,智能工具的应用正不断拓展到我们工作和生活的各个角落。从任务规划到项目执行,再到任务管理,作者深入探讨了这款工具在不同场景下的表现和潜力。通过具体的应用实例,文章展示了扣子空间如何帮助用户...

spider-flow:开源的可视化方式定义爬虫方案

spider-flow简介spider-flow是一个爬虫平台,以可视化推拽方式定义爬取流程,无需代码即可实现一个爬虫服务。spider-flow特性支持css选择器、正则提取支持JSON/XML格式...

solon-flow 你好世界!

solon-flow是一个基础级的流处理引擎(可用于业务规则、决策处理、计算编排、流程审批等......)。提供有“开放式”驱动定制支持,像jdbc有mysql或pgsql等驱动,可...

新一代开源爬虫平台:SpiderFlow

SpiderFlow:新一代爬虫平台,以图形化方式定义爬虫流程,不写代码即可完成爬虫。-精选真开源,释放新价值。概览Spider-Flow是一个开源的、面向所有用户的Web端爬虫构建平台,它使用Ja...

通过 SQL 训练机器学习模型的引擎

关注薪资待遇的同学应该知道,机器学习相关的岗位工资普遍偏高啊。同时随着各种通用机器学习框架的出现,机器学习的门槛也在逐渐降低,训练一个简单的机器学习模型变得不那么难。但是不得不承认对于一些数据相关的工...

鼠须管输入法rime for Mac

鼠须管输入法forMac是一款十分新颖的跨平台输入法软件,全名是中州韵输入法引擎,鼠须管输入法mac版不仅仅是一个输入法,而是一个输入法算法框架。Rime的基础架构十分精良,一套算法支持了拼音、...

Go语言 1.20 版本正式发布:新版详细介绍

Go1.20简介最新的Go版本1.20在Go1.19发布六个月后发布。它的大部分更改都在工具链、运行时和库的实现中。一如既往,该版本保持了Go1的兼容性承诺。我们期望几乎所...

iOS 10平台SpriteKit新特性之Tile Maps(上)

简介苹果公司在WWDC2016大会上向人们展示了一大批新的好东西。其中之一就是SpriteKitTileEditor。这款工具易于上手,而且看起来速度特别快。在本教程中,你将了解关于TileE...

程序员简历例句—范例Java、Python、C++模板

个人简介通用简介:有良好的代码风格,通过添加注释提高代码可读性,注重代码质量,研读过XXX,XXX等多个开源项目源码从而学习增强代码的健壮性与扩展性。具备良好的代码编程习惯及文档编写能力,参与多个高...

Telerik UI for iOS Q3 2015正式发布

近日,TelerikUIforiOS正式发布了Q32015。新版本新增对XCode7、Swift2.0和iOS9的支持,同时还新增了对数轴、不连续的日期时间轴等;改进TKDataPoin...

ios使用ijkplayer+nginx进行视频直播

上两节,我们讲到使用nginx和ngixn的rtmp模块搭建直播的服务器,接着我们讲解了在Android使用ijkplayer来作为我们的视频直播播放器,整个过程中,需要注意的就是ijlplayer编...

IOS技术分享|iOS快速生成开发文档(一)

前言对于开发人员而言,文档的作用不言而喻。文档不仅可以提高软件开发效率,还能便于以后的软件开发、使用和维护。本文主要讲述Objective-C快速生成开发文档工具appledoc。简介apple...

macOS下配置VS Code C++开发环境

本文介绍在苹果macOS操作系统下,配置VisualStudioCode的C/C++开发环境的过程,本环境使用Clang/LLVM编译器和调试器。一、前置条件本文默认前置条件是,您的开发设备已...