目录

1. 异常是什么

2 让事情沿你指定的轨道出错

2.1 raise 语句

2.2 自定义的异常类

3. 捕获异常

3.1 不用提供参数

3.2 多个except 子句

3.3 捕获多种异常

3.4 捕获对象

3.5 捕获所有异常

3.6 能够运行时才结束

3.7 finally

4. 异常和函数

5 异常之禅

6. 不那么异常的情况


1. 异常是什么

Python使用异常对象 来表示异常状态,并在遇到错误时引发 异常。异常对象未被处理(或捕获 )时,程序将终止并显示一条错误消息(traceback)。

>>> 1 / 0
Traceback (most recent call last):File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero

如果异常只能用来显示错误消息,就没多大意思了。但事实上,每个异常都是某个类(这里是ZeroDivisionError )的实例。你能以各种方式引发和捕获这些实例,从而逮住错误并采取措施,而不是放任整个程序失败。

2 让事情沿你指定的轨道出错

2.1 raise 语句

要引发异常,可使用raise 语句,并将一个类(必须是Exception 的子类)或实例作为参数。将类作为参数时,将自动创建一个实例。下面的示例使用的是内置异常类Exception :

# 引发的是通用异常,没有指出出现了什么错误。
>>> raise Exception
Traceback (most recent call last):File "<stdin>", line 1, in ?
Exception# 添加了错误消息hyperdrive overload
>>> raise Exception('hyperdrive overload')
Traceback (most recent call last):File "<stdin>", line 1, in ?
Exception: hyperdrive overload>>> raise ArithmeticError
Traceback (most recent call last):File "<stdin>", line 1, in ?
ArithmeticError

一些内置的异常类:

类名

描述

Exception

几乎所有的异常类都是从它派生而来的
AttributeError 引用属性或给它赋值失败时引发
OSError 操作系统不能执行指定的任务(如打开文件)时引发,有多个子类
IndexError 使用序列中不存在的索引时引发,为LookupError 的子类
KeyError 使用映射中不存在的键时引发,为LookupError 的子类
NameError 找不到名称(变量)时引发
SyntaxError 代码不正确时引发
TypeError 将内置操作或函数用于类型不正确的对象时引发
ValueError 将内置操作或函数用于这样的对象时引发:其类型正确但包含的值不合适
ZeroDivisionError 在除法或求模运算的第二个参数为零时引发

2.2 自定义的异常类

就像创建其他类一样,但务必直接或间接地继承Exception (这意味着从任何内置异常类派生都可以)。因此,自定义异常类的代码类似于下面这样:

class SomeCustomException(Exception):pass

3. 捕获异常

可以对异常进行处理,通常称之为捕获异常。

可使用try/except 语句。

# 这个程序运行正常,除非第二个数为零。
x = int(input('Enter the first number: '))
y = int(input('Enter the second number: '))
print(x / y)
try:x = int(input('Enter the first number: '))y = int(input('Enter the second number: '))print(x / y)
except ZeroDivisionError:print("The second number can't be zero!")

异常从函数向外传播到调用函数的地方。如果在这里也没有被捕获,异常将向程序的最顶层传播。这意味着你可使用try/except 来捕获他人所编写函数引发的异常。

3.1 不用提供参数

捕获异常后,如果要重新引发它(即继续向上传播),可调用raise 且不提供任何参数。

现在看一个能够“抑制”异常ZeroDivisionError 的计算器类。如果启用了这种功能,计算器将打印一条错误消息,而不让异常继续传播。在与用户交互的会话中使用这个计算器时,抑制异常很有用;但在程序内部使用时,引发异常是更佳的选择(此时应关闭“抑制”功能)。下面是这样一个类的代码:

class MuffledCalculator:muffled = Falsedef calc(self, expr):try:return eval(expr)except ZeroDivisionError:if self.muffled:print('Division by zero is illegal')else:raise

发生除零行为时,如果启用了“抑制”功能,方法calc 将(隐式地)返回None 。换而言之,如果启用了“抑制”功能,就不应依赖返回值。

>>> calculator = MuffledCalculator()
>>> calculator.calc('10 / 2')
5.0
>>> calculator.calc('10 / 0') # 关闭了抑制功能
Traceback (most recent call last): File "<stdin>", line 1, in ?File "MuffledCalculator.py", line 6, in calcreturn eval(expr)File "<string>", line 0, in ?
ZeroDivisionError: integer division or modulo by zero
>>> calculator.muffled = True
>>> calculator.calc('10 / 0')
Division by zero is illegal

关闭抑制功能时,捕获了异常ZeroDivisionError ,但继续向上传播它。

如果无法处理异常,在except 子句中使用不带参数的raise 通常是不错的选择,但有时你可能想引发别的异常。在这种情况下,导致进入except 子句的异常将被作为异常上下文 存储起来,并出现在最终的错误消息中。

>>> try:
...     1/0
... except ZeroDivisionError:
...     raise ValueError
...
Traceback (most recent call last):File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

可使用raise ... from ... 语句来提供自己的异常上下文,也可使用None 来禁用上下文。

>>> try:
...     1/0
... except ZeroDivisionError:
...     raise ValueError from None
...
Traceback (most recent call last):File "<stdin>", line 4, in <module>
ValueError

3.2 多个except 子句

前面的程序如果输入一个非数字值,将引发另一种异常。

由于该程序中的except 子句只捕获ZeroDivisionError 异常,这种异常将成为漏网之鱼,导致程序终止。为同时捕获这种异常,可在try/except 语句中再添加一个except 子句。

try:x = int(input('Enter the first number: '))y = int(input('Enter the second number: '))print(x / y)
except ZeroDivisionError:print("The second number can't be zero")
except TypeError:print("That wasn't a number, was it?")

现在使用if 语句来处理将更加困难。如何检查一个值能否用于除法运算呢?方法有很多,但最佳的方法无疑是尝试将两个值相除,看看是否可行。

另外,注意到异常处理并不会导致代码混乱,而添加大量的if 语句来检查各种可能的错误状态将导致代码的可读性极差。

3.3 捕获多种异常

如果要使用一个except 子句捕获多种异常,可在一个元组中指定这些异常。

# 如果用户输入字符串、其他非数字值或输入的第二个数为零,都将打印同样的错误消息
try:x = int(input('Enter the first number: '))y = int(input('Enter the second number: '))print(x / y)
except (ZeroDivisionError, TypeError, NameError):print('Your numbers were bogus ...')

在except 子句中,异常两边的圆括号很重要。一种常见的错误是省略这些括号,这可能导致你不想要的结果。

3.4 捕获对象

要在except 子句中访问异常对象本身,可使用两个而不是一个参数。

try:x = int(input('Enter the first number: '))y = int(input('Enter the second number: '))print(x / y)
except (ZeroDivisionError, TypeError) as e:print(e)

3.5 捕获所有异常

即使程序处理了好几种异常,还是可能有一些漏网之鱼。例如,对于前面执行除法运算的程序,如果用户在提示时不输入任何内容就按回车键,将出现一条错误消息,还有一些相关问题出在什么地方的信息(栈跟踪 )。

这种异常未被try/except 语句捕获,这理所当然,因为你没有预测到这种问题,也没有采取相应的措施。在这些情况下,与其使用并非要捕获这些异常的try/except 语句将它们隐藏起来,还不如让程序马上崩溃,因为这样你就知道什么地方出了问题。

如果你就是要使用一段代码捕获所有的异常,只需在except 语句中不指定任何异常类即可。

try:x = int(input('Enter the first number: '))y = int(input('Enter the second number: '))print(x / y)
except:print('Something wrong happened ...')

在大多数情况下,更好的选择是使用except Exception as e 并对异常对象进行检查。这样做将让不是从Exception 派生而来的为数不多的异常成为漏网之鱼,其中包括SystemExit 和KeyboardInterrupt ,因为它们是从BaseException (Exception 的超类)派生而来的。

3.6 能够运行时才结束

在有些情况下,在没有出现异常时执行一个代码块很有用。为此,可像条件语句和循环一样,给try/except 语句添加一个else 子句。

try:print('A simple task')
except:print('What? Something went wrong?')
else:print('Ah ... Itwent as planned.')

不断的要求用户输入数字,直到能够执行除法运算为止。仅当没有引发异常时,才会跳出循环(这是由else 子句中的break 语句实现的)。换而言之,只要出现错误,程序就会要求用户提供新的输入。

while True:try:x = int(input('Enter the first number: '))y = int(input('Enter the second number: '))value = x / yprint('x / y is', value)except:print('Invalid input. Please try again.')else:break
while True:try:x = int(input('Enter the first number: '))y = int(input('Enter the second number: '))value = x / yprint('x / y is', value)except Exception as e:print('Invalid input:', e)print('Please try again')else:break

3.7 finally

finally 子句,可用于在发生异常时执行清理工作。这个子句是与try 子句配套的。

不管try 子句中发生什么异常,都将执行finally 子句。

虽然使用del 来删除变量是相当愚蠢的清理措施,但finally 子句非常适合用于确保文件或网络套接字等得以关闭。

x = None
try:x = 1 / 0
finally:print('Cleaning up ...')del x

也可在一条语句中同时包含try 、except 、finally 和else (或其中的3个)。

try:1 / 0
except NameError:print("Unknown variable")
else:print("That went well!")
finally:print("Cleaning up.")

4. 异常和函数

异常和函数有着天然的联系。如果不处理函数中引发的异常,它将向上传播到调用函数的地方。如果在那里也未得到处理,异常将继续传播,直至到达主程序(全局作用域)。如果主程序中也没有异常处理程序,程序将终止并显示栈跟踪消息。

>>> def faulty():
...     raise Exception('Something is wrong')
...
>>> def ignore_exception():
...     faulty()
...
>>> def handle_exception():
...     try:
...         faulty()
...     except:
...         print('Exception handled')
...
>>> ignore_exception()
Traceback (most recent call last):File '<stdin>', line 1, in ?File '<stdin>', line 2, in ignore_exceptionFile '<stdin>', line 2, in faulty
Exception: Something is wrong
>>> handle_exception()
Exception handled

faulty 中引发的异常依次从faulty 和ignore_exception 向外传播,最终导致显示一条栈跟踪消息。调用handle_exception 时,异常最终传播到handle_exception ,并被这里的try/except 语句处理。

5 异常之禅

异常处理并不是很复杂。如果你知道代码可能引发某种异常,且不希望出现这种异常时程序终止并显示栈跟踪消息,可添加必要的try/except 或try/finally 语句(或结合使用)来处理它。

有时候,可使用条件语句来达成异常处理实现的目标,但这样编写出来的代码可能不那么自然,可读性也没那么高。另一方面,有些任务使用if/else 完成时看似很自然,但实际上使用try/except 来完成要好得多。

假设有一个字典,你要在指定的键存在时打印与之相关联的值,否则什么都不做。

这段代码很直观,但效率不高(虽然这里的重点是代码简洁),因为它必须两次查找'occupation' 键:一次检查这个键是否存在(在条件中),另一次获取这个键关联的值,以便将其打印出来。

def describe_person(person):print('Description of', person['name'])print('Age:', person['age'])if 'occupation' in person:print('Occupation:', person['occupation'])

在这里,函数直接假设存在'occupation' 键。如果这种假设正确,就能省点事:直接获取并打印值,而无需检查这个键是否存在。如果这个键不存在,将引发KeyError 异常,而except 子句将捕获这个异常。

def describe_person(person):print('Description of', person['name'])print('Age:', person['age'])try:print('Occupation:', person['occupation'])except KeyError: pass

检查对象是否包含特定的属性时,try/except 也很有用。例如,假设你要检查一个对象是否包含属性write ,可使用类似于下面的代码:

在这里,try 子句只是访问属性write ,而没有使用它来做任何事情。如果引发了AttributeError 异常,说明对象没有属性write ,否则就说明有这个属性

try:obj.write
except AttributeError:print('The object is not writeable')
else:print('The object is writeable')

这里在效率方面的提高并不大(实际上是微乎其微)。一般而言,除非程序存在性能方面的问题,否则不应过多考虑这样的优化。关键是在很多情况下,相比于使用if/else ,使用try/except 语句更自然,也更符合Python的风格。

6. 不那么异常的情况

如果你只想发出警告 ,指出情况偏离了正轨,可使用模块warnings 中的函数warn 。

>>> from warnings import warn
>>> warn("I've got a bad feeling about this.")
__main__:1: UserWarning: I've got a bad feeling about this.
>>>

警告只显示一次。如果再次运行最后一行代码,什么事情都不会发生。

如果其他代码在使用你的模块,可使用模块warnings 中的函数filterwarnings 来抑制你发出的警告(或特定类型的警告),并指定要采取的措施,如"error" 或"ignore" 。

>>> from warnings import filterwarnings
>>> filterwarnings("ignore")
>>> warn("Anyone out there?")
>>> filterwarnings("error")
>>> warn("Something is very wrong!")
Traceback (most recent call last):File "<stdin>", line 1, in <module>
UserWarning: Something is very wrong!

引发的异常为UserWarning 。发出警告时,可指定将引发的异常(即警告类别),但必须是Warning 的子类。如果将警告转换为错误,将使用你指定的异常。另外,还可根据异常来过滤掉特定类型的警告。

>>> filterwarnings("error")
>>> warn("This function is really old...", DeprecationWarning)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
DeprecationWarning: This function is really old...
>>> filterwarnings("ignore", category=DeprecationWarning)
>>> warn("Another deprecation warning.", DeprecationWarning)
>>> warn("Something else.")
Traceback (most recent call last):File "<stdin>", line 1, in <module>
UserWarning: Something else.

07. Python-异常相关推荐

  1. python异常捕获和写到mysql_python捕获数据库异常

    [转载]Python简介 Python是一种解析性的,交互式的,开源的面向对象的编程语言,类似于Perl.Tcl.Scheme或Java. Python是一种面向对象.直译式的计算机程序设计语言,也是 ...

  2. Python培训教程分享:Python异常机制

    ​ 在学习Python技术的时候,我们经常会遇到一些异常,例如导致程序在运行过程中出现的中断或退出,我们都称之为异常,大多数的异常都不会被程序处理,而是以错误信息的形式展现出来.本期Python培训教 ...

  3. 一行代码简化Python异常信息:错误清晰指出,排版简洁美观 | 开源分享

    鱼羊 发自 凹非寺 量子位 报道 | 公众号 QbitAI 即使是Python,报错时也令人头大. 看着这一堆乱麻,不知道是该怀疑人生,还是怀疑自己手残. 那么,Python异常输出美化工具Prett ...

  4. python——异常(1),捕获特定异常

    python--异常(1),捕获特定异常 参考文章: (1)python--异常(1),捕获特定异常 (2)https://www.cnblogs.com/kekefu/p/12317986.html ...

  5. python异常之ModuleNotFoundError: No module named ‘test01inner02‘

    python异常之ModuleNotFoundError: No module named 'test01inner02' 参考文章: (1)python异常之ModuleNotFoundError: ...

  6. python 异常处理中try else语句的使用

    python 异常处理中try else语句的使用 参考文章: (1)python 异常处理中try else语句的使用 (2)https://www.cnblogs.com/journey-mk5/ ...

  7. python代码大全表解释-【初学】Python异常代码含义对照表

    原标题:[初学]Python异常代码含义对照表 Python常见的异常提示及含义对照表如下: 异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 Keyb ...

  8. python错误-python异常与错误区别

    错误和异常概念 错误: 1.语法错误:代码不符合解释器或者编译器语法 2.逻辑错误:不完整或者不合法输入或者计算出现问题 异常:执行过程中出现万体导致程序无法执行 1.程序遇到逻辑或者算法问题 2.运 ...

  9. Python异常及处理方法总结

    原文:https://blog.csdn.net/polyhedronx/article/details/81589196 作者:polyhedronx 调试Python程序时,经常会报出一些异常,异 ...

  10. python超神之路:python异常对照表

    python异常对照表 异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入^C) Excep ...

最新文章

  1. python私有属性和property装饰器_python – 在使用@property装饰器时在属性的s...
  2. Mysql 755和750权限,chmod 755 究竟是什么鬼?
  3. R语言dplyr包的top_n函数返回dataframe或tibble的前N行数据、dplyr包的top_frac函数返回dataframe或tibble的前百分之N(N%)的数据
  4. 新买的笔记本电脑怎么分盘_电脑怎么增加C盘空间?黑客教你不花钱增加C盘空间...
  5. not null primary key什么意思_为什么我使用了索引,索引却没有生效?
  6. python库怎么学啊最好_最常用的几个python库--学习引导
  7. 搞嵌入式Linux,做底层还是应用?底层要掌握哪些技能?
  8. 简单的线性模型实现tensorflow权重的生成和调用,并且用类的方式实现参数共享
  9. 领域驱动设计(DDD):领域和子域
  10. win10安装账户卡住_win10安装卡着不动怎么处理 解决win10安装卡死方法
  11. AcWing 858. Prim算法求最小生成树(稠密图)
  12. Julia: 趣!,13579分别在一本168页书的页码中出现的次数
  13. (2022最新)Java毕业设计参考题目-题目新颖(值得收藏)
  14. 大篆汉字对照表_篆书的写法(附篆楷常用字对照表)
  15. Android 蓝牙AVRCP 专题 (2)----- 耳机端设置绝对音量,手机端收到音量改变Register Notification
  16. 路由器显示DNS服务器异常,路由器dns异常怎么办
  17. 快速创建精彩的Flash游戏之一:Flash游戏引擎及框架介绍
  18. 【qq音乐歌曲下载转换为mp3格式】
  19. 一篇网络流的好blog
  20. 风格迁移1-02:Liquid Warping GAN(Impersonator)-源码模型测试-报错解决

热门文章

  1. ubuntu20.04 ros 采集velodyne激光雷达数据
  2. vsftp中anon_world_readable_only参数具体使用
  3. 简单几步解决ie打不开闪退的问题 亲测有效
  4. 大数据文字游戏_移动的大数据指南:千字以内的文章传播率最高
  5. 安装sklearn-poter遇到报错(TypeError:‘encoding‘ is an invalid keyword argument for this function)
  6. BZOJ 1127 [POI2008]KUP 最大子矩阵
  7. 养殖环控程序 三菱plc可以带物联网模块,7寸触摸屏程序
  8. 程序员必备英语单词清单
  9. S.M.A.R.T原则:目标管理概念 - 让你的管理规范化
  10. js中的~~:转换成整型数字的神器(效率)