在Python中处理警告
off999 2024-11-20 20:03 37 浏览 0 评论
我们每个人都会遇到这种情况: 你写了一些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/
译者:天天向上
相关推荐
- 笔记本电脑选哪个品牌比较好
-
1、苹果APPLE/美国2、戴尔DELL/美国3、华为HUAWEI/中国4、小米MI/中国5、微软Microsoft/美国6、联想LENOVO/中国7、惠普HP/美国8、华硕ASUS/...
- 10系列显卡排名(10系显卡性能排行)
-
十系显卡指NVIDIAGeForce10系列,是英伟达研发并推出的图形处理器系列,被用以取代NVIDIAGeForce900系列图形处理器。新系列采用帕斯卡微架构来代替之前的麦克斯韦微架构,并...
-
- 最新win7系统下载(windows7最新版本下载)
-
最简单的方法就是,下载完镜像文件后,直接把镜像文件解压,解压到非C盘,然后在解压文件里面找到setup.exe,点击运行即可。安装系统完成后,在C盘找到一个Windows.old(好几个GB,是旧系统打包在这里,垃圾文件了)删除即可。扩展资...
-
2026-01-15 06:43 off999
- 哪个电脑管家软件好用(哪个电脑管家好用些)
-
腾讯电脑管家吧,因为这个是杀毒和管理合一的,占用内存小,因此显得更为简洁,使电脑运行更加流畅此外电脑诊所,工具箱以及4+1的杀毒模式让腾讯电脑管家也收到了广泛的关注4+1杀毒引擎,管家反病毒引擎、金山...
- 怎么进入win7安全模式(怎么进入win7安全模式界面)
-
方法如下:1、首先进入Win7系统,然后使用Win键+R组合键打开运行框,输入“Msconfig”回车进入系统配置。2、在打开的系统配置中,找到“引导”选项,然后单击,选择Win7的引导项,然后在“安...
- 怎么分区固态硬盘(怎样分区固态硬盘)
-
固态硬盘的分区方法与传统机械硬盘基本相同,以下是一个简单的步骤:1.打开磁盘管理工具:在Windows操作系统中,按下Win+X键,选择"磁盘管理"。或者打开控制面板,在"...
-
- 笔记本声卡驱动怎么下载(笔记本如何下载声卡)
-
1、在浏览器中输入并搜索,然后下载并安装。2、安装完成后打开360驱动大师,它就会自动检测你的电脑需要安装或升级的驱动。3、检测完毕后,我们可以看到我们的声卡驱动需要安装或升级,点击安装或升级,就会开始自动安装或升级声卡了。4、升级过程中会...
-
2026-01-15 05:43 off999
- win10加快开机启动速度(加快开机速度 win10)
-
一、启用快速启动功能1.按win+r键调出“运行”在输入框输入“gpedit.msc”按回车调出“组策略编辑器”?2.在“本地组策略编辑器”依次打开“计算机配置——管理模块——系统——关机”在右侧...
-
- excel的快捷键一览表(excel的快捷键一览表超全)
-
Excel快捷键大全的一些操作如下我在工作中经常使用诸如word或Excel之类的办公软件。我相信每个人都不太熟悉这些办公软件的快捷键。使用快捷键将提高办公效率,并使您的工作更加轻松快捷。。例如,在复制时,请使用CtrI+C进行复制,...
-
2026-01-15 05:03 off999
- 华硕u盘启动按f几(华硕u盘装系统按f几进入)
-
F8。1、开机的同时按F8进入BIOS。2、在Boot菜单中,置secure为disabled。3、BootListOption置为UEFI。4、在1stBootPriority中usb—HD...
- 手机云电脑怎么用(手机云端电脑)
-
使用手机云电脑,您首先需要安装相应的云电脑应用。例如,华为云电脑APP。在安装并打开应用后,您将看到一个显示器的图标,这就是您的云电脑。点击这个图标,您将被连接到一个预装有Windows操作系统和必要...
- ie11浏览器怎么安装(ie11浏览器安装步骤)
-
如果IE浏览器11版本你发现无法正常安装,那么很可能是这样几个原因,一个就是电脑的存储空间不够到时无法安装,再有就是网络的问题,如果没有办法安装的话就不要再安装了,本身这个IE浏览器并不是多好用,你最...
- 台式机重装系统win7(台式机怎么重装win7)
-
下面主要介绍两种方法以重装系统:一、U盘重装系统准备:一台正常开机的电脑和一个U盘1、百度下载“U大师”(老毛桃、大白菜也可以),把这个软件下载并安装在电脑上。2、插上U盘,选择一键制作U盘启动(制作...
- 字母下划线怎么打出来(字母下的下划线怎么去不掉)
-
第一步,在电脑上找到文字处理软件WPS,双击即自动新建一个新文档。第二步,在文档录入需要处理的字母和数字,双击鼠标或拖动鼠标选择要处理的内容。第三步,在页面的左上方的横向菜单栏,找到字母U的按纽,点击...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
python入门到脱坑 输入与输出—str()函数
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
失业程序员复习python笔记——条件与循环
-
系统u盘安装(win11系统u盘安装)
-
Python 批量卸载关联包 pip-autoremove
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
