异常
异常就是不正常的情况。Python提供了强大的异常处理机制。python使用异常对象来表示异常状态,并在遇到错误时引发异常。
>>> 1/0
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
1/0
ZeroDivisionError: division by zero
上面是一个分子为零的异常。异常未被捕获时,程序将终止并返回一条错误信息(Traceback)。
自主引发异常——raise语句
出现异常时,将自动引发异常。也可以使用raise语句自主引发异常。看下面的例子。
>>> raise Exception
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
raise Exception
Exception
上面是释放一个内置异常类Exception,也可以在异常里添加错误信息。
>>> raise Exception('Test example')
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
raise Exception('Test example')
Exception: Test example
一些内置的异常类
类名 | 描述 |
---|---|
Exception | 几乎所有的异常类都是从它派生而来的 |
AttributeError | 引用属性或给它赋值失败时引发 |
OSError | 操作系统不能执行指定的任务(如打开文件)时引发,有多个子类 |
IndexError | 使用序列中不存在的索引时引发,为LookupError的子类 |
KeyError | 使用映射中不存在的键时引发,为LookupError的子类 |
NameEroor | 找不到名称(变量)时引发 |
SyntaxError | 代码不正确时引发 |
TypeError | 将内置操作或函数用于类型不正确的对象时引发 |
ValueError | 将内置操作或函数用于这样的对象时引发:其类型正确但包含的值不合适 |
ZeroDivisionError | 在除法或者求模运算的第二个参数为零时引发 |
自定义创建异常类
除了释放内置的异常类,也可以自定义创建异常类。创建异常类很简单,和创建其他类一样。但是需要直接或者间接的继承Exception(这意味着从任何内置异常类派生都可以。)
>>> class Firstexception(Exception):
pass
>>> raise Firstexception
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
raise Firstexception
Firstexception
捕获异常 try/excepy语句
接下来是最有趣的地方了,捕获异常。如果你觉得某段代码可能会引发异常,可以使用try / except语句捕获异常。
>>> try:
x = int(input('data1: '))
y = int(input('data2: '))
print(x / y)
except ZeroDivisionError:
print("The second number can't be zero!")
data1: 2
data2: 0
The second number can't be zero!
捕获异常后,可以在except语句块中进行相应的处理措施。如果想要重新引发异常(异常继续向上传播),可调用raise语句且不提供任何参数。看下面这个例子,类MuffledCalculator中的属性muffled如果为TRUE时,异常会被处理。当muffled为false时,异常会被再次引发。
>>> class MuffledCalculator:
muffled = False
def clac(self, expr):
try:
return eval(expr)
except ZeroDivisionError:
if self.muffled:
print('Division by zero is illeagl')
else:
raise
>>> calculator = MuffledCalculator()
>>> calculator.clac('10 / 2')
5.0
>>> calculator.clac('10 / 0')
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
calculator.clac('10 / 0')
File "<pyshell#11>", line 5, in clac
return eval(expr)
File "<string>", line 1, in <module>
ZeroDivisionError: division by zero
>>> calculator.muffled = True
>>> calculator.clac('1 / 0')
Division by zero is illeagl
如果无法处理异常,except语句中使用raise是一个很好的选择。另外,如果想要引发其他异常,那么导致进入except语句的异常将被作为异常上下文存储起来。
>>> try:
a = 1/0
except ZeroDivisionError:
raise ValueError
Traceback (most recent call last):
File "<pyshell#37>", line 2, in <module>
a = 1/0
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<pyshell#37>", line 4, in <module>
raise ValueError
ValueError
也可使用raise…from…自己提供上下文。raise…from…None表示禁用上下文。
>>> try:
a = 1/0
except ZeroDivisionError:
raise ValueError from Exception
Exception
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<pyshell#47>", line 4, in <module>
raise ValueError from Exception
ValueError
>>> try:
a = 1/0
except ZeroDivisionError:
raise ValueError from None
Traceback (most recent call last):
File "<pyshell#49>", line 4, in <module>
raise ValueError from None
ValueError
如果想要处理多个异常。如果多个异常想要分开处理,可以使用多个except语句。
>>> try:
x = int(input('data1: '))
y = int(input('data2: '))
print(x / y)
except ZeroDivisionError:
print("The second number can't be zero")
except TypeError:
print("That wasn't a number, was it?")
data1: 1
data2: 0
The second number can't be zero
多个异常处理方法一样时,可在一个元组里指定这些异常。
>>> try:
x = int(input('data1: '))
y = int(input('data2: '))
print(x / y)
except (ZeroDivisionError, TypeError, NameError):
print('Your numbers were bogus...')
data1: 1
data2: 0
Your numbers were bogus...
else 子句
异常与句块可以加上else语句。会在没有异常时执行。
>>> while True:
try:
x = int(input('data1:'))
y = int(input('data2:'))
value = x/y
print('x/y is', value)
except:
print('Invalid input. Please try again.')
else:
break
data1:1
data2:0
Invalid input. Please try again.
data1:jk
Invalid input. Please try again.
data1:j
Invalid input. Please try again.
data1:jkj
Invalid input. Please try again.
data1:2
data2:jkj
Invalid input. Please try again.
data1:1
data2:2
x/y is 0.5
finally字句
最后介绍一下finally子句。可用于在发生异常时执行清理工作。不管try子句中是否发生异常都会执行finally子句。
>>> try:
1/0
except NameError:
print('Unknown variable')
else:
print('That went well!')
finally:
print('Cleaning up.')
Cleaning up.
Traceback (most recent call last):
File "<pyshell#88>", line 2, in <module>
1/0
ZeroDivisionError: division by zero
警告
再说一下警告(处理不那么严重的情况)把,警告可使用warning模块中的函数warn。
>>> from warnings import warn
>>> warn('hhhh')
Warning (from warnings module):
File "__main__", line 1
UserWarning: hhhh
小结
- 异常对象: 异常情况(如发生错误)是用异常对象表示的。对于异常情况,有多种处理方式;如果忽略,将导致程序终止。
- 引发异常: 可使用raise语句来引发异常。它将一个异常类或异常实例作为参数,但你可以提供两个参数(异常和错误消息)。如果在except子句中调用raise时没有提供参数,它将重新引发该子句捕获的异常。
- 捕获异常: 要捕获异常,可在try语句中使用except子句。在except子句中,如果没有指定异常类,将捕获所有的异常。你可以指定多个异常类,方法是将它们放在元组中。如果想except提供两个参数,第二个参数将关联到异常对象。在同一条try/except语句中,可包含多个except子句,以便对不同的异常采取不同的措施。
- 警告: 警告类似于异常,但(通常)只打印一条错误信息。你可以指定警告类别,它们是warning的子类。
本章学习的函数:
函数 | 描述 |
---|---|
warnings.filterwarnings(action, category=Warning, …) | 用于过滤警告 |
warnings.warn(message, category=None) | 用于发出警告 |