先看下else的使用:
try:
...
exception:
...
else:
...
只有在try中没有发生任何异常,所有代码完全成功的情况下才会转入else
再看下finally:
finally是无论是否捕捉到异常都会执行的一句,finally 可以单独和try搭配,也可以和except,包括else一起配合使用
try: A
except MyException: B
else: C
finally: D
执行顺序可能为A-B-D或A-C-D finally 单独和try连用时,不是用来捕捉异常,常常是用来维持一致的行为。
当try范围中产生一个异常时,会立即跳转到finally,finally执行完毕后,会继续向上一层引发异常
- 一个这样写的理由是如果在 finally 的语句块内发生了一个异常,你可以创建一个同现有的异常 处理器在同一个(外)层次的异常处理器来处理它.这样,从本质上来说,就可以同时处理在原始的 try 语句块和 finally 语句块中发生的错误.这种方法唯一的问题是,当 finally 语句块中的确发生异常 时,你会丢失原来异常的上下文信息,除非你在某个地方保存了它.
反对这种写法的一个理由是:在很多情况下,异常处理器需要做一些扫尾工作,而如果你在异常 处理之前,用 finally 语句块中释放了某些资源,你就不能再去做这项工作了.简单的说,finally 语句 块并不是如你所想的是"最终的(final)"了.
一个最终的注意点:如果 finally 中的代码引发了另一个异常或由于 return,break,continue 语 法而终止,原来的异常将丢失而且无法重新引发.
参考:python 核心编程
python try/except/finally
- x = 'abc'
- def fetcher(obj, index):
- return obj[index]
- fetcher(x, 4)
输出:
- File "test.py", line 6, in <module>
- fetcher(x, 4)
- File "test.py", line 4, in fetcher
- return obj[index]
- IndexError: string index out of range
第一: try不仅捕获异常,而且会恢复执行
- def catcher():
- try:
- fetcher(x, 4)
- except:
- print "got exception"
- print "continuing"
输出:
- got exception
- continuing
第二:无论try是否发生异常,finally总会执行
- def catcher():
- try:
- fetcher(x, 4)
- finally:
- print 'after fecth'
输出:
- after fecth
- Traceback (most recent call last):
- File "test.py", line 55, in <module>
- catcher()
- File "test.py", line 12, in catcher
- fetcher(x, 4)
- File "test.py", line 4, in fetcher
- return obj[index]
- IndexError: string index out of range
第三:try无异常,才会执行else
- def catcher():
- try:
- fetcher(x, 4)
- except:
- print "got exception"
- else:
- print "not exception"
输出:
- got exception
- def catcher():
- try:
- fetcher(x, 2)
- except:
- print "got exception"
- else:
- print "not exception"
输出:
- not exception
else作用:没有else语句,当执行完try语句后,无法知道是没有发生异常,还是发生了异常并被处理过了。通过else可以清楚的区分开。
第四:利用raise传递异常
- def catcher():
- try:
- fetcher(x, 4)
- except:
- print "got exception"
- raise
输出:
- got exception
- Traceback (most recent call last):
- File "test.py", line 37, in <module>
- catcher()
- File "test.py", line 22, in catcher
- fetcher(x, 4)
- File "test.py", line 4, in fetcher
- return obj[index]
- IndexError: string index out of range
raise语句不包括异常名称或额外资料时,会重新引发当前异常。如果希望捕获处理一个异常,而又不希望
异常在程序代码中消失,可以通过raise重新引发该异常。
第五:except(name1, name2)
- def catcher():
- try:
- fetcher(x, 4)
- except(TypeError, IndexError):
- print "got exception"
- else:
- print "not exception"
捕获列表列出的异常,进行处理。若except后无任何参数,则捕获所有异常。
- def catcher():
- try:
- fetcher(x, 4)
- except:
- print "got exception"
一、异常的捕获 异常的捕获有以下几种方法: :使用try和except语句 try: block except [exception,[data…]]: block try: block except [exception,[data...]]: block else: block 该种异常处理语法的规则是: • 执行try下的语句,如果引发异常,则执行过程会跳到第一个except语句。 • 如果第一个except中定义的异常与引发的异常匹配,则执行该except中的语句。 • 如果引发的异常不匹配第一个except,则会搜索第二个except,允许编写的except数量没有限制。 • 如果所有的except都不匹配,则异常会传递到下一个调用本代码的最高层try代码中。 • 如果没有发生异常,则执行else块代码。 示例代码: try: f = open(“file.txt”,”r”) except IOError, e: print e 捕获到的IOError错误的详细原因会被放置在对象e中,然后运行该异常的except代码块,也可以使用以下方法来捕获所有的异常: try: a=b b=c except Exception,ex: print Exception,":",ex 使用except子句需要注意的事情,就是多个except子句截获异常时,如果各个异常类之间具有继承关系,则子类应该写在前面,否则父类将会直接截获子类异常,放在后面的子类异常也就不会执行到了。 :使用try跟finally try: block finally: block 该语句的执行规则是: • 执行try下的代码。 • 如果发生异常,在该异常传递到下一级try时,执行finally中的代码。 • 如果没有发生异常,则执行finally中的代码。 第二种try语法在无论有没有发生异常都要执行代码的情况下是很有用的,例如我们在python中打开一个文件进行读写操作,我在操作过程中不管是否出现异常,最终都是要把该文件关闭的。 这两种形式相互冲突,使用了一种就不允许使用另一种,而功能又各异。 二、手工引发引发一个异常 在Python中,要想引发异常,最简单的形式就是输入关键字raise,后跟要引发的异常的名称。异常名称标识出具体的类:Python异常是那些类的对象,执行raise语句时,Python会创建指定的异常类的一个对象,raise语句还可指定对异常对象进行初始化的参数,为此,请在异常类的名称后添加一个逗号以及指定的参数(或者由参数构成的一个元组)。 示例代码: try: raise MyError #自己抛出一个异常 except MyError: print 'a error' raise ValueError,'invalid argument' 捕捉到的内容为: type = VauleError message = invalid argument 三、跟踪查看异常 发生异常时,Python能“记住”引发的异常以及程序的当前状态,Python还维护着traceback(跟踪)对象,其中含有异常发生时与函数调用堆栈有关的信息,异常可能在一系列嵌套较深的函数调用中引发,程序调用每个函数时,Python会在“函数调用堆栈”的起始处插入函数名,一旦异常被引发,Python会搜索一个相应的异常处理程序。 如果当前函数中没有异常处理程序,当前函数会终止执行,Python会搜索当前函数的调用函数,并以此类推,直到发现匹配的异常处理程序,或者Python抵达主程序为止,这一查找合适的异常处理程序的过程就称为“堆栈辗转开解”(Stack Unwinding)。解释器一方面维护着与放置堆栈中的函数有关的信息,另一方面也维护着与已从堆栈中“辗转开解”的函数有关的信息。 try: block except: traceback.print_exc() 四、采用sys模块回溯最后的异常 import sys try: block except: info=sys.exc_info() print info[],] 或者以如下的形式: import sys tp,val,td = sys.exc_info() sys.exc_info()的返回值是一个tuple, (type, value/message, traceback) 这里的type是异常的类型,value/message是异常的信息或者参数,traceback包含调用栈信息的对象,从这点上可以看出此方法涵盖了traceback。 以上都是错误处理的理论知识,接下来我们要动手设计一个自己的异常处理类,用来记录异常日志,将错误的日志按照每小时一个文件的频率,保存到我们指定的位置。代码如下: #coding:utf- #基于python2. import logging,os,time,traceback class LOG: def __init__(self,logger): self.fileHandlerName = '' self.fileHandler = None self.loggerName = logger self.logger = logging.getLogger(logger) self.logger.setLevel(logging.DEBUG) self.formatter = logging.Formatter("=========================ntime:%(asctime)s nlogger:%(name)s nlevel:%(levelname)s nfile:%(filename)s nfun:%(funcName)s nlineno:%(lineno)d nmessage:%(message)s") # 控制台 ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) ch.setFormatter(self.formatter) self.logger.addHandler(ch) path = os.path.abspath(os.path.dirname(__file__)) + '/log/'+self.loggerName+'/' print 'log path=',path def setfh(self): fname = time.strftime("%Y%m%d%H") if fname!=self.fileHandlerName: #移除原来的句柄 if self.fileHandler!=None : self.logger.removeHandler(self.fileHandler) #设置日志文件保存位置 path = os.path.abspath(os.path.dirname(__file__)) + '/log/'+self.loggerName+'/' print path if os.path.isdir(path) == False: os.makedirs(path) fh = logging.FileHandler(path+fname+'.log') fh.setLevel(logging.DEBUG) fh.setFormatter(self.formatter) self.logger.addHandler(fh) self.fileHandlerName = fname self.fileHandler = fh #格式化日志内容 def _fmtInfo(self,msg): : msg = traceback.format_exc() return msg else: _tmp = [msg[]] _tmp.append(traceback.format_exc()) return 'n**********n'.join(_tmp) #封装方法 def debug(self,*msg): _info = self._fmtInfo(msg) try: self.setfh() self.logger.debug(_info) except: print 'mylog debug:' + _info def error(self,*msg): _info = self._fmtInfo(msg) try: self.setfh() self.logger.error(_info) except: print 'mylog error:' + _info def info(self,*msg): _info = self._fmtInfo(msg) try: self.setfh() self.logger.error(_info) except: print 'mylog info:' + _info def warning(self,*msg): _info = self._fmtInfo(msg) try: self.setfh() self.logger.error(_info) except: print 'mylog warning:' + _info if __name__=='__main__': log = LOG('fight') try: print / except: log.error() #使用系统自己的错误描述 try: print / except: log.error('搞错了,分母不能为0') #使用自己的错误描述
异常处理 . 抛出异常和自定义异常 Python用异常对象(exception object)表示异常情况,遇到错误后,会引发异常。如果异常对象并未被处理或捕捉,程序就会用所谓的回溯(Traceback,一种错误信息)终止执行。 1.1 raise 语句 Python中的raise 关键字用于引发一个异常,基本上和C#和Java中的throw关键字相同,如下所示: # -- coding: utf- -- def ThorwErr(): raise Exception("抛出一个异常") # Exception: 抛出一个异常 ThorwErr() raise关键字后面是抛出是一个通用的异常类型(Exception),一般来说抛出的异常越详细越好,Python在exceptions模块内建了很多的异常类型,通过使用dir函数来查看exceptions中的异常类型,如下: import exceptions # ['ArithmeticError', 'AssertionError'.....] print dir(exceptions) 传递异常 捕捉到了异常,但是又想重新引发它(传递异常),可以使用不带参数的raise语句即可: # -- coding: utf- -- class MuffledCalculator: muffled = False def calc(self,expr): try: return eval(expr) except ZeroDivisionError: if self.muffled: print 'Division by zero is illegal' else: raise 1.2 自定义异常类型 Python中也可以自定义自己的特殊类型的异常,只需要要从Exception类继承(直接或间接)即可: class SomeCustomException(Exception): pass . 捕捉异常 和C#中的try/catch类似,Python中使用try/except关键字来捕捉异常,如下: # -- coding: utf- -- try: print / except ZeroDivisionError: print '除数不能为0'2.1 捕捉多个异常 在一个except语句只捕捉其后声明的异常类型,如果可能会抛出的是其他类型的异常就需要再增加一个except语句了,或者也可以指定一个更通用的异常类型比如:Exception,如下: # -- coding: utf- -- try: print /' except ZeroDivisionError: print '除数不能为0' except Exception: print '其他类型异常' 为了捕获多个异常,除了声明多个except语句之外,还可以在一个except语句之后将多个异常作为元组列出来即可: # -- coding: utf- -- try: print /' except (ZeroDivisionError,Exception): print '发生了一个异常' .2获取异常信息 每个异常都会有一些异常信息,一般情况下我们应该把这些异常信息记录下来: # -- coding: utf- -- try: print /' except (ZeroDivisionError,Exception) as e: # unsupported operand type(s) for /: 'int' and 'str' print e . finally子句 finally子句和try子句联合使用但是和except语句不同,finally不管try子句内部是否有异常发生,都会执行finally子句内的代码。所有一般情况下,finally自己常常用于关闭文件或者在Socket中。 # -- coding: utf- -- try: print /' except (ZeroDivisionError,Exception): print '发生了一个异常' finally: print '不管是否发生异常都执行'
之前在学习python的时候有整理过python异常处理的文章,不够简单也不够完整,所以决定再整理一篇,算做补充。 http://www.cnblogs.com/fnng/archive/2013/04/28/3048356.html python shell >>> open('abc.txt','r') Traceback (most recent call last): File , in <module> IOError: [Errno ] No such file or directory: 'abc.txt' 打开一个不存在的文件abc.txt 文件,当系统找不到abc.txt 文件时,就会抛出给我们一个IOError类型的错误,No such file or directory:abc.txt (没有abc.txt这样的文件或目录) Try...except... 假如,我们已经知道这种类型的错误,那么就可以通过一个异常扑捉来扑捉这个错误。我们可以通过try...except 来接收这个错误。打开文件写入: try: open("abc.txt",'r') except IOError: pass 再来运行程序就会看不到任何错误,因为我们用except 接收了这个IOError错误。pass 表示实现了相应的实现,但什么也不做。 假如我不是打开一个文件,而是输出一个没有定义的变量呢? try: print aa except IOError: pass 显然,在上面的代码中我并没有对aa 赋值,运行结果: Traceback (most recent call last): File , in <module> print aa NameError: name 'aa' is not defined 我们已经用except 接收错误了,为什么错误还是还是抛出来了。如果你细心会发现这一次的错误类型是NameError ,而我接收类型是IOError ,所以要想接收这个print的错误,那么需要修改接收错误的类型为NameError 虽然,我知道print 语句是可能会抛一个NameError 类型的错误,虽然接收了这个类型错误,但我不知道具体的错误提示信息是什么。那么,我能不能把错误信息打印出来呢?当然可以: try: print aa except NameError, msg: print msg 我们在接收错误类型的后面定义一个变量msg用于接收具体错误信息, 然后将msg接收的错误信息打印。再来运行程序: name 'aa' is not defined 现在只打印了一行具体错误信息。 异常的抛出机制: 、如果在运行时发生异常,解释器会查找相应的处理语句(称为handler). 、要是在当前函数里没有找到的话,它会将异常传递给上层的调用函数,看看那里能不能处理。 、如果在最外层(全局“main”)还是没有找到的话,解释器就会退出,同时打印出traceback以便让用户找到错误产生的原因。 注意:虽然大多数错误会导致异常,但一个异常不一定代表错误,有时候它们只是一个警告,有时候它们可能是一个终止信号,比如退出循环等。 try...finally... try...finally...子句用来表达这样的情况: 我们不管线捕捉到的是什么错误,无论错误是不是发生,这些代码“必须”运行,比如文件关闭,释放锁,把数据库连接返还给连接池等。 创建文件poem.txt tryf.py import time try: f = file('poem.txt') while True: # our usual file-reading idiom line = f.readline() : break time.sleep() print line, finally: f.close() print 'Cleaning up...closed the file' 运行程序(在windows命令提示符或linux终端下运行): ...$ python tryf.py abc efg ^CCleaning up...closed the file Traceback (most recent call last): File , in <module> time.sleep() KeyboardInterrupt 程序读poem.txt文件中每一行数据打印,但是我有意在每打印一行之前用time.sleep方法暂停2秒钟。这样做的原因是让程序运行得慢一些。在程序运行的时候,按Ctrl-c中断/取消程序。 我们可以观察到KeyboardInterrupt异常被触发,程序退出。但是在程序退出之前,finally从句仍然被执行,把文件关闭。 到目前为止,我们只讨论了如何捕捉异常,那么如何抛出异常呢? Raise抛出异常 使用raise来抛出一个异常: tryr.py #coding=utf- filename = raw_input('please input file name:') if filename=='hello': raise NameError('input file name error !') 程序要求用户输入一个文件名,如果用户输入的文件名是hello ,那么抛出一个NameError的异常,用户输入hello 和NameError异常之间没有任何必然联系,我只是人为的通过raise来这样定义,我当然也可以定义称TypeError ,但我定义的异常类型必须是python提供的。 附录: 常见的python异常类型
当你的程序中出现异常情况时就需要异常处理。比如当你打开一个不存在的文件时。当你的程序中有一些无效的语句时,Python会提示你有错误存在。
下面是一个拼写错误的例子,print写成了Print。Python是大小写敏感的,因此Python将引发一个错误:
>>> Print 'Hello World' File "", line 1 Print 'Hello World' ^ SyntaxError: invalid syntax >>> print 'Hello World' Hello World
1、try...except语句
try...except语句可以用于捕捉并处理错误。通常的语句放在try块中,错误处理语句放在except块中。示例如下:
#!/usr/bin/python # Filename: try_except.py import sys try: s = raw_input('Enter something --> ') except EOFError:#处理EOFError类型的异常 print '/nWhy did you do an EOF on me?' sys.exit() # 退出程序 except:#处理其它的异常 print '/nSome error/exception occurred.' print 'Done'
运行输出如下:
$ python try_except.py Enter something --> Why did you do an EOF on me? $ python try_except.py Enter something --> Python is exceptional! Done
说明:每个try语句都必须有至少一个except语句。如果有一个异常程序没有处理,那么Python将调用默认的处理器处理,并终止程序且给出提示。
2、引发异常
你可以用raise语句来引发一个异常。异常/错误对象必须有一个名字,且它们应是Error或Exception类的子类。
下面是一个引发异常的例子:
#!/usr/bin/python #文件名: raising.py class ShortInputException(Exception): '''你定义的异常类。''' def __init__(self, length, atleast): Exception.__init__(self) self.length = length self.atleast = atleast try: s = raw_input('请输入 --> ') if len(s) < 3: raise ShortInputException(len(s), 3) # raise引发一个你定义的异常 except EOFError: print '/n你输入了一个结束标记EOF' except ShortInputException, x:#x这个变量被绑定到了错误的实例 print 'ShortInputException: 输入的长度是 %d, / 长度至少应是 %d' % (x.length, x.atleast) else: print '没有异常发生.'
运行输出如下:
$ python raising.py 请输入 --> 你输入了一个结束标记EOF $ python raising.py 请输入 --> --> ab ShortInputException: 输入的长度是 2, 长度至少应是 3 $ python raising.py 请输入 --> abc 没有异常发生.
3、try...finally语句
当你正在读文件或还未关闭文件时发生了异常该怎么办呢?你应该使用try...finally语句以释放资源。示例如下:
运行输出如下:
$ python finally.py Programming is fun When the work is done Cleaning up...closed the file Traceback (most recent call last): File "finally.py", line 12, in ? time.sleep(2) KeyboardInterrupt
说明:我们在两秒这段时间内按下了Ctrl-c,这将产生一个KeyboardInterrupt异常,我们并没有处理这个异常,那么Python将调用默认的处理器,并终止程序,在程序终止之前,finally块中的语句将执行。
python中的异常 异常是指程序中的例外,违例情况。异常机制是指程序出现错误后,程序的处理方法。当出现错误后,程序的执行流程发生改变,程序的控制权转移到异常处理。 Exception类是常用的异常类,该类包括StandardError,StopIteration, GeneratorExit, Warning等异常类。 StandardError类是python中的错误异常,如果程序上出现逻辑错误, 将引发该异常。StandardError类是所有内敛异常的基类,放置在默认的命名空间中,因此使用IOEroor, EOFError, ImportError等类,不需要导入exception模块。 StopIteration类判断循环是否执行到尾部,如果循环到尾部,则抛出该异常。 GeneratorExit类是由Generator函数引发的异常,当调用close()时引发该异常。 Warning类表示程序中的代码引起的警告。 python中的异常使用继承结构创建,可以在异常处理程序中捕获基类异常,也可以捕获各种子类异常,python中使用try...except语句捕获异常,异常子句定义在try子句后面。 try...except的使用方法 try...except用于处理问题语句,捕获可能出现的异常。try子句中的代码块放置可能出现异常的语句,except子句中的代码块处理异常。 演示try...except语句捕获IOError异常 try: file("hello.txt", "r") #如果文件不存在,引发异常 print "读文件" except IOError: #捕获IO异常 print "文件不存在" except: #其它异常 print "程序异常" python与Java的异常处理模式相似,异常处理语句也可以嵌套,演示如下: try: s = "hello" try: print s[] + s[] print s[] - s[] except TypeError: print "字符串不支持减法运算" except: print "异常" 如果外层try子句中的代码引发异常,程序将直接跳转到外层try对应的except子句,而内部的try子句将不会被执行。 try...finally的使用方法 try...except后还可以添加一个finally子句。无论异常是否发生,finally子句都会被执行。所有的finally子句通常用于关闭因异常而不能释放的系统资源。 try: f = open("hello.txt", "r") try: print f.read() except: print "读文件异常" finally: print "释放资源" f.close() except IOError: print "文件不存在" 使用raise抛出异常 当程序出现错误,python会自动引发异常,也可以通过raise显示地引发异常。一旦执行了raise语句,raise后面的语句将不能执行。 演示raise用法 try: s = None if s is None: print "s 是空对象" raise NameError #如果引发NameError异常,后面的代码将不能执行 print len(s) except TypeError: print "空对象没有长度" 自定义异常 python允许程序员自定义异常,用于描述python中没有涉及的异常情况,自定义异常必须继承Exception类,自定义异常按照命名规范以"Error"结尾,显示地告诉程序员这是异常。自定义异常使用raise语句引发,而且只能通过人工方式触发。 from __future__ import division class DivisionException(Exception): def __init__(self, x, y): Exception.__init__ (self, x, y) #调用基类的__init__进行初始化 self.x = x self.y = y if __name__ == "__main__": try: x = y = : #如果大于0, 则不能被初始化,抛出异常 print x/y raise DivisionException(x, y) except DivisionException,div: #div 表示DivisionException的实例对象 print "DivisionExcetion: x/y = %.2f" % (div.x/div.y) assert语句的使用 assert语句用于检测某个条件表达式是否为真。assert语句又称为断言语句,即assert认为检测的表达式永远为真,if语句中的条件判断都可以使用assert语句检测。