写代码的时候,出现错误必不可免。
看下面这段代码:
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 <cell line: 4>() 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 <cell line: 4>() 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 <cell line: 3>() 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!
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 <cell line: 1>() 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.