第 7 章 异常与断言
7 EXCEPTIONS AND ASSERTIONS
曲政 / 2018-04-21
“exception” 的含义在 Python 中有什么不同?
英语中:not norm, thus rare.
python 里:not rare, everywhere.
最常出现的 exception 的类型有哪四种?
- TypeError
- IndexError
- NameError
- ValueError
7.1 Handing Exceptions
exception 有哪两种命运?
- raise an error, program terminates
- be handled, and program continues
为什么要处理 exception?
除了因为 bug 引发的 exception,更多的 exception 可以并应该被预计到,然后得到相应的处理。
比如 - 尝试打开不存在的文件。 - 用户输入数据不合理。
一个检验输入数据是否合理的函数?
def read_val (val_type, request_msg, error_msg):
while True:
val = input (request_msg + " ")
try:
return (val_type (val))
except ValueError:
print (val, error_msg)
def test_read_val ():
print (read_val (int, "Enter an integer:", "is not an integer"))
test_read_val ()
解释两句:
- 它有 “多型性”,polymorphic.
- int 是 type,也是 function,是 first-class object。在 python 里,一切都是对象。所谓 first-class object 可以理解为,它能作为函数的 arguments 和 return value。
为什么要承担处理 exception 的麻烦?
- 让程序不中止。
- 明确区分函数返回值的意义。比如
int ('abc')
返回的是 abc 的编码值,还是 None? - 忘记了写 except,程序会死机等,这是一个明确的 bug 信号。
except 有几种写法?
except:
except ValueError:
except (ValueError, TypeError):
7.2 Exceptions as a Control Flow Mechanism
函数计算出错了,怎么让它告诉我们?
大多数编程语言是让函数返回一个特定的值,类似 Python 的 None
,让程序判断是否得到 None,是否出错。
有更好的做法:让函数自己就把错误信息显示出来,在它内部检查是否符合 specification,如果不符合,就把不符合的部分反馈出来。
在函数内可以用 raise exceptionName (arguments)
语句,构建错误信息。在函数外,用 except ValueError as msg: print ("some coment", msg)
把信息显示出来。
比如:
def get_ratios (vect1, vect2):
"""Assumes : vect1 and vect2 are equal lenght lists of numbers.
Returns: s list containing the meaningful values of vect1 [1]/vect2 [2]."""
ratios = []
for index in range (len (vect1)):
try:
ratios.append (vect1 [index]/vect2 [index])
except ZeroDivisionError:
ratios.append (float ('nan'))
except:
raise ValueError ('get_ratios called with bad arguments')
return ratios
def test_get_ratios ():
try:
print (get_ratios ([1.0, 2.0, 7.0, 6.0], [1.0, 2.0, 0.0, 3.0]))
print (get_ratios ([], []))
print (get_ratios ([1.0, 2.0], [3.0]))
except ValueError as msg:
print (msg)
输出
$ python3 fe_7_2_get_ratios.py
[1.0, 1.0, nan, 2.0]
[]
get_ratios called with bad arguments
###nan
怎么用?
可以用 float ("nan")
把它作为浮点数使用,包含它的 expression 值也是 nan。
ratios.append (float ('nan'))
[1.0, 1.0, nan, 2.0]
为什么还要用except
包含不符合 specificaion 的情况?
检验一下又不会增加多少计算成本,而防范一下,defensive programming and checking,是个好习惯。
except:
raise ValueError ('get_ratios called with bad arguments')
7.3 Assertions
为什么要加 assertion?
另一种 defensive programming 的习惯。检验中间值,检验函数返回值。
assert Boolean expression, argument
以上,2018-04-15 记。