写出来的python程序不一定是完全正确的。即使所有逻辑都对了,但是用户在使用过程的不当,也会导致程序运行出错。
本文结构:
常见的异常类型
如何处理异常
如何自定义异常
1. 常见的异常大概有以下的一些:
NameError 尝试访问一个没有声明的变量
如图,在f() 函数里,试图打印一个未被定义的变量yy,当调用f()函数时,将会抛出一个NameError 的异常。
ImportError 无法引入模块或包;可能路径不存在
如图,试图import 模块abc12,但是由于abc12 并不是已经被定义了的模块,所以程序就会抛出ImportError 的异常。
IndentationError 语法错误(的子类);代码没有正确对齐
如图1,如果空格键和Tab键混用,也是会抛出IndentationError 这个语法错误。a前用了空格键,b前用了tab键。
如图2,就是明显的没有对齐了,语法错误。
SyntaxError 语法错误
IndexError 索引超出序列范围
如图,访问列表时,访问了超出索引范围,就会抛出IndexError 异常
KeyError 请求一个不存在的字典关键字
如图,对字典dic 的访问,使用了一个不存在的key值,就会抛出KeyError异常
IOError 输入输出错误(比如要读的文件不存在)
如图,用open() 函数尝试打开一个不存在的文件,则会抛出IOError异常。但是如果是使用‘w’的方式打开,则不存在的文件会被创建。
AttributeError 访问未知对象属性
ValueError 传给函数的参数类型不正确,比如int()函数传入字符串函数
如图,给int()函数传入一个非数字的字符参数,会抛出ValueError 异常
UnboundLocalError 试图访问一个还未被设置的局部变量
如图,变量y 在函数f()外面已经被定义,但是在f()方法里,它是一个局部变量,y还没使用,不能直接对其进行赋值操作。
但是,在第二个f()函数的定义中,直接print 打印y值,这样做是不会抛出异常的。
KeyboardInterrupt 键盘中断异常,例如ctrl+c
time.sleep(60) 让程序休眠60秒,在休眠的过程中,按下ctrl+c,将会终端time.sleep()进程,同时抛出KeyboardInterrupt异常。
2. 如何处理异常
在python中处理异常,需要对异常捕获,再处理。在python中捕获异常的代码大概是这样的:
try:
try_suite
except Exception1,Exception2,...,Argument:
exception_suite
#other exception block
else:
no_exceptions_detected_suite
finally:
always_execute_suite
如上,在try 里捕获异常,如果try_suite 抛出了异常,那么异常就会被捕获。
然后except 对捕获的异常类型进行判断,如果是想要捕获的异常类型,则在excepttion_suite 里做一些处理。
Exception1, Exception2 是Exception 异常类型对象,例如在文章第一部分列出的常见异常类型NameError,IndexError等异常类型。
Argument
else 语句,是当try 没有捕获到任何异常时,就会执行no_exception_detected_suite 里的操作。但是,else 部分并不是必须的,它可以被省略。即使省略了else 部分,甚至将except 部分也省略了,也是可以的。只要有try 部分就可以对异常进行捕获了。
finally 语句,无论是否捕获到异常,异常处理是否被执行了,都一定会将finally部分执行的。所以,通常会将,文件关闭,资源回收这些操作放在finally部分执行。finally 部分也是可以省略的。
2.1 try...except... 结构
大概的结构:
try:
try_suite
except Exception:
except_suite
只要try_suite 抛出异常,可能会被try 语句捕获,try 捕获后,就会将异常交给except 语句处理,如果异常是except 需要判定的Exception 则,执行except_suite 的语句。
例子:
如上图,try 捕获到ZeroDivisionError, 通过Except 判定是需要捕获的,则执行print 输出代码块。
try...except... 可以一次捕获多个错误,可以将异常写在同一个except 里,也可以分开在多个except 语句,例如:
如上图,分别用两个except 语句处理了try语句捕获到的ZeroDivisionError 和ValueError 的异常。
如果不知道需要捕获什么异常,except 可以什么异常类型都不带。例如:
如图,两个函数里的try...except... 语句块里的except 都没有带具体的Exception类型,所以只要在try 语句里捕获到的任何异常,交给except 语句都会执行except_suite 语句。
当然,除了将多个异常写在不同的except 语句里,也可以将多个异常类型写在一个except 里,例如:
try :
try_suite
except Exception1, Exception2,...:
except_suite
except 语句除了能捕获异常类型外,还可以创建异常类型的实例,通过异常的实例可以 知道有关异常的更多信息,这对我们跟踪和处理异常是很有帮助的。异常的实例,就是except Exception1,Exception2,...,Argument里的Argument参数了。Exception1,Exception2等都是异常的类型,如果try 捕获到的异常,是except 需要判定的,那么Argument 就会被except 创建为该类型的实例。通过实例,可以知道更多的异常信息。例如:
如图,try 捕获了一个除零异常,并且创建了一个异常类型的实例Argument。
通过打印Argume 的信息,可以更具体地知道异常的信息。
2.2 try...except...else...
try:
try_suite
except Exceptions1,...argument:
except_suite
else:
other_suite
try...except... 就不用多说了。else类似于if...elsse... 结构的else.当try 没有捕获到异常,那么else 语句中的other_suite 语句将会执行。
如上图,第一次打开当前路径存在的文件,没有异常抛出,则执行了except 的语句。第二次,尝试打开一个当前路径不存在的文件,则抛出了IOError 的异常。
2.3 finally...子句
finally 语句,无论有没有异常被捕获,它都会执行。可以try和finally 配合使用,也可以和except 和else一起配合使用。
例如:
try:
fd = open('/home/hell/hell.txt')
except IOError, re:
print "Error: no such file"
else:
print "cool~"
finally:
print "end..."
3. 自定义异常
通过自定义异常类,但是这个类需要继承父类Exception 异常类.
(1) 定义了一个继承自Exception 的自定义异常类FunError ,类里的__str__()方法被定义为return 一条信息,通常作为异常信息。
(2) 定义一个f() 函数,在函数里抛出异常,使用关键字raise。raise 关键字可以用来抛出一个异常。
(3) 所以,如果调用f() 函数,那么函数就会抛出一个FunError()的异常类。
(4) 当抛出FunError() 异常类时,异常类的实例同时被创建,那么类的__str__() 方法就会被调用,所以,就可以看到异常信息FunError: I am a func Error.
所以,自定义的FunError 类,也是可以被try 来捕获的,例如:
如图,在try 里调用f() 函数,它会抛出异常,被except 捕获,将异常类的实例e 打印,打印的就是类的__str__() 方法的信息。
转载于:https://blog.51cto.com/hellocjq/1863677