python中的异常处理和调试
今天我们就来扒一扒异常处理和调试的那些事……(蜗牛一手还拿着咬了半拉的煎饼)
首先要明白的一点是,程序发生异常之后,程序的流程会改变,程序的控制权将会转移到异常处理器。异常发生时,如果没有程序处理异常,那python会接受处理,python解释器将输出一些相关的信息并终止程序的运行。
python中常见的几种异常:
- python中的异常采用继承结构创建。
try……except
这大概是每个语言都有的异常机制了。
将可能出现问题的代码块放到try中,如果出现了异常,则会自动生成一个异常对象,这个对象包括了异常的具体信息和错误位置等。
举个栗子:
try:
file('hello.txt','r')
print "读文件"
except IOError:
print "file is not excist"
except:
print "程序异常"
读一个不存在的文件,会产生异常,直接跳到第四行。
后边的那个except是不会执行了。因为上边捕获了IOError。
try……except……finally
是try……except的升级版,后边加一个finally语句,意思是无论异常是否发生,finally子句都会被执行。
- 其实finally异常多用于关闭因为异常而不能的关闭的已经打开的资源。
举个栗子:
try:
f=file('hello.txt','r')
print "读文件"
except IOError:
print "file is not excist"
finally:
f.close()
执行上述代码有错。
为什么?
等下再说为什么有错,但是这个结构是对的,也很好的解释了“finally”语句用于关闭打开的资源。
再来看错误:
NameError: name ‘f’ is not defined
f定义在try的语句块中,是局部变量,在finally的语句块中f没有作用域。
正确的代码童鞋们可以试试(提示:try语句可以嵌套哦)
raise语句
发生错误时,python自动引发异常,但是也可以通过raise显示引发异常。但是一旦执行了raise语句,raise语句之后的代码不会执行。
自定义异常
自己可以定义异常,用于弥补python没有定义的异常
自己定义的异常必须继承Exception类。
自己定义的异常以Error结尾。因为不是python提供的异常,所以只能使用raise手动去引发(抛出)异常。
(以下内容来自廖雪峰的教程)
class FooError(StandardError):
pass
def foo(s):
n = int(s)
if n==0:
raise FooError('invalid value: %s' % s)
return 10 / n
if __name__=="__main__":
foo(0)
首先定义了自己的异常类型FooError,他一定要继承一个异常的基类:StandardError,它是python提供的一个基类。
这里弄个断点,我们去看一下异常的继承关系。
python2.5 版本的异常定义在exception模块中,并继承了基类BaseException。注意所有的错误类型都继承自 BaseException 。
Excepetion是最常用的异常类,包括StandardError,StopIteration,GeneratorExit等异常类。
断点回来,继承了StandardError的FooError,啥类体都没有,pass
在后边的raise FooError(‘invalid value: %s’ % s)语句中,记得要手动raise一个自定义的异常。
结果:
raise FooError('invalid value: %s' % s)
__main__.FooError: invalid value: 0
可以跟踪自己的异常
再来看个例子:(来自廖雪峰教程)
def foo(s):
n = int(s)
return 10 / n
def bar(s):
try:
return foo(s) * 2
except StandardError, e:
print 'Error!'
raise
def main():
bar('0')
main()
在 bar() 函数中,我们明明已经捕获了错误,但是,打印一个 Error! 后,又把错误通过 raise 语句抛出去了,这不
有病么?
其实这种错误处理方式不但没病,而且相当常见。捕获错误目的只是记录一下,便于后续追踪。但是,由于当前函
数不知道应该怎么处理该错误,所以,最恰当的方式是继续往上抛,让顶层调用者去处理。
- raise 语句如果不带参数,就会把当前错误原样抛出。
assert语句
assert和if差不多是近亲,用法很像。
只是assert 不满足的时候会抛出assert异常。
>>> t=("hello",)
>>> assert len(t)>=1
>>> t=("hello")
>>> assert len(t)>=1
>>> assert len(t)==1
第一行不会有问题,因为括号里面有逗号,代表这是个元组,而元组里面就一个元素hello。
第三行但如果没这个逗号,python会认为后边是个string,所以第四行没错,而第五行不满足assert条件会抛出AssertError。
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
assert len(t)==1
AssertionError
assert还可以带信息给AssertionError
举个栗子:
>>> month=12
>>> assert 1<=month<=11,"month errors"
结果:
Traceback (most recent call last):
……
AssertionError: month errors
ps:1<=month<=11这样的语句python是支持的。