《python基础教程》学习——python异常
一、异常
1.定义
Python使用异常对象来表示异常状态,并在遇到错误时引发异常。异常对象未被处理(或捕获)时,程序将终止并显示一条错误消息(traceback)。
>>> 1 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
2.自定义异常
class SomeCustomException(Exception): pass
3.自主引发异常与自定义异常信息——raise语句
>>> raise Exception # 自主引发异常,你也可以引发ZeroDivisionError等
Traceback (most recent call last):
File "<stdin>", line 1, in ?
Exception
>>> raise Exception('hyperdrive overload') # 引发异常,并自定义异常信息
Traceback (most recent call last):
File "<stdin>", line 1, in ?
Exception: hyperdrive overload # 结果显示自定义异常信息
4.捕获异常
1)在捕捉到异常的同时,引发另一个异常:
注意:
-
捕捉到一个异常的时候,同时引发另一个异常,导致进入except子句的异常将被作为
异常上下文
存储起来,然后报错信息将会出现两个异常的错误信息
:>>> try: ... 1/0 ... except ZeroDivisionError: ... raise ValueError ... Traceback (most recent call last): File "<stdin>", line 2, in <module> ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 4, in <module> ValueError
-
若你想要去掉except子句的异常报错的话:
>>> try: ... 1/0 ... except ZeroDivisionError: ... raise ValueError from None ... Traceback (most recent call last): File "<stdin>", line 4, in <module> ValueError
2)捕捉多个异常
运行代码的时候,有时候不只出现一个异常,所以需要多个异常处理。
如:
>>> 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!")
...
Enter the first number: 10
Enter the second number: "Hello,world!"
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
ValueError: invalid literal for int() with base 10: '"Hello,world!"'
上例中,可以看出,在捕捉处理了ZeroDivisionError之后,出现了新的异常,所以针对这种异常,也需要使用except子句进行处理。
i)多次捕捉,分别处理——多个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 ValueError:
... print("That wasn't a number,was it?")
...
Enter the first number: 10
Enter the second number: "Hello,world!"
That wasn't a number,was it?
ii)一次捕捉,一次处理——一个except子句
1.相同处理:打印相同信息
>>> try:
... x = int(input('Enter the first number: '))
... y = int(input('Enter the second number: '))
... print(x/y)
... except(ZeroDivisionError,TypeError,NameError,ValueError):
... raise #可以使用print("xxxx") 无论什么错误,都输出同一句话
...
Enter the first number: 10
Enter the second number: 0
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ZeroDivisionError: division by zero
2.不同处理:打印对应的错误信息
>>> try:
... x = int(input('Enter the first number: '))
... y = int(input('Enter the second number: '))
... print(x/y)
... except(ZeroDivisionError,ValueError) as e:
... print(e)
...
Enter the first number: 10
Enter the second number: 0
division by zero
Enter the first number: 10
Enter the second number: "Hello,world!"
invalid literal for int() with base 10: '"Hello,world!"'
iii)一次捕捉所有的异常
以上的两种方式,捕捉的异常都可能不全,这种方法捕捉全部异常。
while True:
try:
x = int(input('Enter the first number: '))
y = int(input('Enter the second number: '))
value = x / y
print('x / y is', value)
except:
print('Invalid input. Please try again.')
else:
break
“ try:... except:...
” 捕获所有的异常很危险:
- 会隐藏你有心理准备的错误信息。
- 隐藏你没有考虑过的错误。
- 捕获不是从Exception派生的异常
其中包括SystemExit和KeyboardInterrupt(从BaseException——Exception的超类 派生而来的异常,例如:用户使用Ctrl + C终止执行的企图、调用函数sys.exit来终止执行的企图等)。
在大多数情况下,更好的选择是使用except Exception as e
并对异常对象进行检查,以免捕捉到无需捕捉的异常。
>>> while True:
... try:
... x = int(input('Enter the first number: '))
... y = int(input('Enter the second number: '))
... value=x/y
... print('x / y is',value)
... except Exception as e:
... print('Invalid input:',e)
... print('Please try again')
... else:
... break
...
Enter the first number: 1
Enter the second number: 0
Invalid input: division by zero
Please try again
Enter the first number: 10
Enter the second number: "Hello,world!"
Invalid input: invalid literal for int() with base 10: '"Hello,world!"'
Please try again
Enter the first number: 1
Enter the second number:
Invalid input: invalid literal for int() with base 10: ''
Please try again
Enter the first number: 'x'
Invalid input: invalid literal for int() with base 10: "'x'"
Please try again
Enter the first number: quuux
Invalid input: invalid literal for int() with base 10: 'quuux'
Please try again
Enter the first number: 10
Enter the second number: 2
x / y is 5.0
3)语句
try.. except...[else...][finally...]
注意:
- else :
当没有引发异常的时候,不会进入except内,而是执行else内的代码。 - finally :
try子句执行完毕后:
i)若存在except子句和else子句,则先执行,最后执行finally子句。
ii)若不存在,则直接进入finally子句。 - 通常finally可用于在发生异常时执行清理工作:
>>> x=None # ZeroDivisionError将导致根本没有机会给它赋值,进而导致在finally子句中对其执行del时引发未捕获的异常。
>>> try:
... x=1/0
... finally:
... print('Cleaning up...')
... del x
...
Cleaning up...
Traceback (most recent call last): #在清理工作结束后才崩溃
File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero
5.函数调用与异常
如果函数A将引发异常,而函数B调用了函数A,函数C调用了函数B,那么:报错信息(函数C → 函数B → 函数A)
>>> 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_exception #最外层函数报错:错误处在调用faulty的地方
File '<stdin>', line 2, in faulty #最内层函数报错
Exception: Something is wrong
>>> handle_exception()
Exception handled
6.不那么异常的情况——警告
Tips:
- 如果你只想发出警告,指出情况偏离了正轨,可使用模块warnings中的函数warn。
- 警告只显示一次。如果再次运行最后一行代码,什么事情都不会发生。
1)指定警告类别
>>> from warnings import filterwarnings
>>> from warnings import warn
# 将警告设置为ignore,则会自动忽略此条警告
>>> filterwarnings("ignore")
>>> warn("This is a warn that I hope you ignore")
>>> warn("ignore2")
# 将警告设置为error,则会引发异常,其信息为你所设置的内容
>>> filterwarnings("error")
>>> warn("This is a warn who will be a exception")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UserWarning: This is a warn who will be a exception
>>> warn("exception2")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UserWarning: exception2
2)不指定警告类别
>>> from warnings import warn
>>> warn("I've got a bad feeling about this.")
__main__:1: UserWarning: I've got a bad feeling about this.
[ 参考文档 ]
- [挪]-Magnus-Lie-Hetland-Python基础教程(第3版)