在python中,try/except语句也主要是用于处理程序正常执行过程中出现的一些异常情况,常见的异常如下:
python程序在发现了except之后的某个错误时,往往会中断不再向下执行
try/except格式:
try:
normal excute block
except A:
Except A handle
except B:
Except B handle
.........
except:
other exception handle
else:
if no exception,get here
finally:
print(hello world)
当try代码块执行出现异常,在except中匹配到了A的异常,则执行了对应A handle的语句;在except中匹配到了B的异常,则执行了对应B handle的语句;没有在列出的异常中则执行except语句,并相应的执行other handle。
注意⚠️:区别except A语句和单独的except 语句,如果没有最后的except:语句,当出现的错误是代码中所有except XX语句都不曾列出的异常,则代码依旧会出现报错,而非给出handle结果。
通过下面的例子来更好的进行理解:
def divide(x, y):
try:
result = x / y
except ZeroDivisionError, e:
print "division by zero! " + str(e)
else:
print "result is", result
finally:
print "executing finally clause"
>>> divide(3,4)
result is 0
executing finally clause
可以发现代码未有报错,执行到了else语句,且finally语句执行
>>>divide(3,0)
division by zero! integer division or modulo by zero
executing finally clause
可以发现分母为0,执行到了except中的异常语句,且finally语句也执行
>>> divide(3,’0‘)
File "<stdin>", line 1
divide(3,’0‘)
^
SyntaxError: invalid syntax
此时代码中有string,而函数中必须是要求数字才能执行,但该函数中except语句只定义了一种ZeroDivisionError的异常,所以最后运行报了SyntaxError
对代码进行优化,如下:
def divideNew(x, y):
try:
result = x / y
except ZeroDivisionError, e:
print "division by zero! " + str(e)
except TypeError:
divideNew(int(x), int(y))
else:
print "result is", result
finally:
print "executing finally clause"
>>> divideNew('4','3')
result is 1
executing finally clause
executing finally clause
可以看到,虽然数字依旧是以string的格式输入,但执行了except TypeError语句,给出了该异常的handle语句,即int(x),int(y)改变了变量类型;
并且可以看到执行了else语句;
出现了两次finally语句是因为执行了一次divideNew('4','3'),又执行了一次divideNew(int('4'),int('3')),再次说明finally 是每次都会执行的语句
对于else语句,当出现异常时,else block不执行;而当程序无异常时,才会执行else语句。
对于finally语句,无论try语句是否出现异常,最后都要执行抓断finally的代码。
根据上面指出的的标准格式,except x必须在exept语句之前,except必须在else和finally之前,finally必须在else之后(最后)。否则会报语法错误。
In Python, can just raise an exception when unable to produce a result consistent with function’s specification
–raise exceptionName(arguments)
Python中,当不能定义某个错误时,可以仅仅raise exceptionName(arguments) :
def getRatios(v1, v2):
ratios = []
for index in range(len(v1)):
try: ratios.append(v1[index]/float(v2[index]))
except ZeroDivisionError: ratios.append(float('NaN')) #NaN = Not a Number
except:
raise ValueError('getRatios called with bad arg')
return ratios
可以看到代码中除去ZeroDivisionError明确指出了错误类型和处理方式,其余的异均返回'getRatios called with bad arg'
下面可以进行相应的测试
try:
print getRatios([1.0,2.0,7.0,6.0],
[1.0,2.0,0.0,3.0])
print getRatios([],[])
print getRatios([1.0,2.0], [3.0])
except ValueError, msg:
print msg
结果如下:
[1.0, 1.0, nan, 2.0]
[]
getRatios called with bad argument
这样分开两部分编辑的code将便于检查异常和整理逻辑,也避免了写在一段函数中的需要考虑的多种情形。
断言 Assertions
断言分两种:pre-Assertions(控制和监督输入)和post Assertions(监督和控制输出)
def avg(grades, weights):
assert not len(grades) == 0, ‘no grades data’
assert len(grades) == len(weights), ‘wrong number grades’
newgr = [convertLetterGrade(elt) for elt in grades]
result = dotProduct(newgr, weights)/len(newgr)
assert 0.0 <= result <= 100.0
return result
第一个pre-Assertions控制了grades变量的输入值必须是长度非零的变量,否则将要raise an AssertionError:输出‘no grades data’
第二个pre-Assertions控制了grades变量和weights变量的长度必须一致,否则将要raise an AssertionError:输出‘wrong number grades
post Assertions则控制了result必须是介于0-100的值才执行return result。
断言Assertions作为一种防御性编程(defensive programming ),可以对输入和变量进行限定,以控制其运行进度。