本文最后更新于 320 天前,其中的信息可能已经过时,如有错误请发送邮件到wuxianglongblog@163.com
异常与警告
异常
写代码的时候,出现错误必不可免。
看下面这段代码:
import math
while True:
text = input('> ')
if text[0] == 'q':
break
x = float(text)
y = math.log10(x)
print(f"log10({x}) = {y}")
这段代码接收命令行的输入,输入为数字时,计算它的对数并输出,直到输入值为 q 为止。
乍看没什么问题,然而输入0或者负数时:
import math
while True:
text = input('> ')
if text[0] == 'q':
break
x = float(text)
y = math.log10(x)
print(f"log10({x}) = {y}")
> -1
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [1], in ()
6 break
7 x = float(text)
----> 8 y = math.log10(x)
9 print(f"log10({x}) = {y}")
ValueError: math domain error |
log10 函数会报错,因为不能接受非正值。
一旦报错,程序就会停止执行,如果不希望程序停止执行,那么可以添加一对 try & except:
import math
while True:
try:
text = input('> ')
if text[0] == 'q':
break
x = float(text)
y = math.log10(x)
print(f"log10({x}) = {y}")
except ValueError:
print("the value must be greater than 0")
> -1
the value must be greater than 0
> 0
the value must be greater than 0
> 1
log10(1.0) = 0.0
> q
捕捉不同的异常类型
假设将这里的 y 更改为 1 / math.log10(x),此时输入 1:
import math
while True:
try:
text = input('> ')
if text[0] == 'q':
break
x = float(text)
y = 1 / math.log10(x)
print(f"1 / log10({x}) = {y}")
except ValueError:
print("the value must be greater than 0")
> 1
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Input In [3], in ()
7 break
8 x = float(text)
----> 9 y = 1 / math.log10(x)
10 print(f"1 / log10({x}) = {y}")
11 except ValueError:
ZeroDivisionError: float division by zero |
程序仍然抛出了异常,原因是ZeroDivisionError
不在可处理的异常中。
可以有两种方法处理这个问题,第一种是捕获异常的父类Exception
:
import math
while True:
try:
text = input('> ')
if text[0] == 'q':
break
x = float(text)
y = 1 / math.log10(x)
print(f"1 / log10({x}) = {y}")
except Exception:
print("invalid value")
> 1
invalid value
> 0
invalid value
> -1
invalid value
> q
第二种是指定多个错误类型:
import math
while True:
try:
text = input('> ')
if text[0] == 'q':
break
x = float(text)
y = 1 / math.log10(x)
print(f"1 / log10({x}) = {y}")
except (ZeroDivisionError, ValueError):
print("invalid value")
> 1
invalid value
> 0
invalid value
> -1
invalid value
> q
还可以分开处理:
import math
while True:
try:
text = input('> ')
if text[0] == 'q':
break
x = float(text)
y = 1 / math.log10(x)
print(f"1 / log10({x}) = {y}")
except ValueError:
print("the value must be greater than 0")
except ZeroDivisionError:
print("the value must not be 1")
> -1
the value must be greater than 0
> 1
the value must not be 1
> 2
1 / log10(2.0) = 3.321928094887362
> q
还可以将异常的具体信息打出来:
import math
while True:
try:
text = input('> ')
if text[0] == 'q':
break
x = float(text)
y = 1 / math.log10(x)
print(f"1 / log10({x}) = {y}")
except Exception as e:
print(e)
> -1
math domain error
> 0
math domain error
> 1
float division by zero
> abcde
could not convert string to float: 'abcde'
> q
可以用raise主动抛出异常,例如判断月份是否在1-12之间:
month = 13
if not 1 <= month <= 12:
raise ValueError(f"{month} must between 1 and 12!")
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [8], in ()
1 month = 13
3 if not 1 <= month <= 12:
----> 4 raise ValueError(f"{month} must between 1 and 12!")
ValueError: 13 must between 1 and 12! |
finally
try/catch 块还有一个可选的关键词 finally。
不管 try 块有没有异常, finally 块的内容总是会被执行,而且会在抛出异常前执行,因此可以用来作为安全保证,比如确保打开的文件被关闭:
try:
print(1)
finally:
print('finally was called.')
1
finally was called.
如果有异常被抛出,finally的部分会在抛出异常前执行:
try:
print(1 / 0)
finally:
print('finally was called.')
finally was called.
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Input In [11], in ()
1 try:
----> 2 print(1 / 0)
3 finally:
4 print('finally was called.')
ZeroDivisionError: division by zero |
异常被处理了,则在最后执行:
try:
print(1 / 0)
except Exception as e:
print(e)
finally:
print('finally was called.')
division by zero
finally was called.