python异常处理try,except,else,finally,raise

先看下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

  1. x = 'abc'  
  2. def fetcher(obj, index):  
  3.     return obj[index]  
  4.   
  5. fetcher(x, 4)  

输出:

  1.   File "test.py", line 6, in <module>  
  2.     fetcher(x, 4)  
  3.   File "test.py", line 4, in fetcher  
  4.     return obj[index]  
  5. IndexError: string index out of range  


第一: try不仅捕获异常,而且会恢复执行

  1. def catcher():  
  2.     try:  
  3.         fetcher(x, 4)  
  4.     except:  
  5.         print "got exception"  
  6.     print "continuing"  

输出:

  1. got exception  
  2. continuing  


第二:无论try是否发生异常,finally总会执行

  1. def catcher():  
  2.     try:  
  3.         fetcher(x, 4)  
  4.     finally:  
  5.         print 'after fecth'  

输出:

  1. after fecth  
  2. Traceback (most recent call last):  
  3.   File "test.py", line 55, in <module>  
  4.     catcher()  
  5.   File "test.py", line 12, in catcher  
  6.     fetcher(x, 4)  
  7.   File "test.py", line 4, in fetcher  
  8.     return obj[index]  
  9. IndexError: string index out of range  


第三:try无异常,才会执行else

  1. def catcher():  
  2.     try:  
  3.         fetcher(x, 4)  
  4.     except:  
  5.         print "got exception"  
  6.     else:  
  7.         print "not exception"  

输出:

  1. got exception  
  1. def catcher():  
  2.     try:  
  3.         fetcher(x, 2)  
  4.     except:  
  5.         print "got exception"  
  6.     else:  
  7.         print "not exception"  

输出:

  1. not exception  

else作用:没有else语句,当执行完try语句后,无法知道是没有发生异常,还是发生了异常并被处理过了。通过else可以清楚的区分开。

第四:利用raise传递异常

  1. def catcher():  
  2.     try:  
  3.         fetcher(x, 4)  
  4.     except:  
  5.         print "got exception"  
  6.         raise  

输出:

  1. got exception  
  2. Traceback (most recent call last):  
  3.   File "test.py", line 37, in <module>  
  4.     catcher()  
  5.   File "test.py", line 22, in catcher  
  6.     fetcher(x, 4)  
  7.   File "test.py", line 4, in fetcher  
  8.     return obj[index]  
  9. IndexError: string index out of range  

raise语句不包括异常名称或额外资料时,会重新引发当前异常。如果希望捕获处理一个异常,而又不希望

异常在程序代码中消失,可以通过raise重新引发该异常。


第五:except(name1, name2)

  1. def catcher():  
  2.     try:  
  3.         fetcher(x, 4)  
  4.     except(TypeError, IndexError):  
  5.         print "got exception"  
  6.     else:  
  7.         print "not exception"  

捕获列表列出的异常,进行处理。若except后无任何参数,则捕获所有异常。

    1. def catcher():  
    2.     try:  
    3.         fetcher(x, 4)  
    4.     except:  
    5.         print "got exception" 
一、异常的捕获
    异常的捕获有以下几种方法:
  

  1:使用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子句截获异常时,如果各个异常类之间具有继承关系,则子类应该写在前面,否则父类将会直接截获子类异常,放在后面的子类异常也就不会执行到了。

    2:使用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[0],":",info[1]


或者以如下的形式:

   
import sys
        tp,val,td = sys.exc_info()

    sys.exc_info()的返回值是一个tuple, (type, value/message, traceback)
    这里的type是异常的类型,value/message是异常的信息或者参数,traceback包含调用栈信息的对象,从这点上可以看出此方法涵盖了traceback。

    以上都是错误处理的理论知识,接下来我们要动手设计一个自己的异常处理类,用来记录异常日志,将错误的日志按照每小时一个文件的频率,保存到我们指定的位置。代码如下:

    #coding:utf-8
    #基于python2.6
    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):
            if len(msg)==0:
                msg = traceback.format_exc()
                return msg
            else:
                _tmp = [msg[0]]
                _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 1/0
        except:
            log.error() #使用系统自己的错误描述
        try:
            print 2/0
        except:
            log.error('搞错了,分母不能为0') #使用自己的错误描述
异常处理
1. 抛出异常和自定义异常
Python用异常对象(exception object)表示异常情况,遇到错误后,会引发异常。如果异常对象并未被处理或捕捉,程序就会用所谓的回溯(Traceback,一种错误信息)终止执行。
 
1.1 raise 语句
Python中的raise 关键字用于引发一个异常,基本上和C#和Java中的throw关键字相同,如下所示:
1 # -- coding: utf-8 --
2 
3 def ThorwErr():
4     raise Exception("抛出一个异常")
5 
6 # Exception: 抛出一个异常
7 ThorwErr() 

raise关键字后面是抛出是一个通用的异常类型(Exception),一般来说抛出的异常越详细越好,Python在exceptions模块内建了很多的异常类型,通过使用dir函数来查看exceptions中的异常类型,如下:
import exceptions
# ['ArithmeticError', 'AssertionError'.....]
print dir(exceptions)

 

传递异常
捕捉到了异常,但是又想重新引发它(传递异常),可以使用不带参数的raise语句即可:
 1 # -- coding: utf-8 --
 2 class MuffledCalculator:
 3     muffled = False
 4     def calc(self,expr):
 5         try:
 6             return eval(expr)
 7         except ZeroDivisionError:
 8             if self.muffled:
 9                 print 'Division by zero is illegal'
10             else:
11                 raise

 
1.2 自定义异常类型
Python中也可以自定义自己的特殊类型的异常,只需要要从Exception类继承(直接或间接)即可:
class SomeCustomException(Exception):
    pass

 
2. 捕捉异常
和C#中的try/catch类似,Python中使用try/except关键字来捕捉异常,如下:
# -- coding: utf-8 --
try:
    print 2/0
except ZeroDivisionError:
    print '除数不能为0'2.1 捕捉多个异常
在一个except语句只捕捉其后声明的异常类型,如果可能会抛出的是其他类型的异常就需要再增加一个except语句了,或者也可以指定一个更通用的异常类型比如:Exception,如下:
# -- coding: utf-8 --
try:
    print 2/'0'
except ZeroDivisionError:
    print '除数不能为0'
except Exception:
    print '其他类型异常'

为了捕获多个异常,除了声明多个except语句之外,还可以在一个except语句之后将多个异常作为元组列出来即可:
# -- coding: utf-8 --
try:
    print 2/'0'
except (ZeroDivisionError,Exception):
    print '发生了一个异常'

 
2.2获取异常信息
每个异常都会有一些异常信息,一般情况下我们应该把这些异常信息记录下来:
# -- coding: utf-8 --
try:
    print 2/'0'
except (ZeroDivisionError,Exception) as e:
    # unsupported operand type(s) for /: 'int' and 'str'
    print e 


 
3. finally子句
finally子句和try子句联合使用但是和except语句不同,finally不管try子句内部是否有异常发生,都会执行finally子句内的代码。所有一般情况下,finally自己常常用于关闭文件或者在Socket中。
# -- coding: utf-8 --
try:
    print 2/'0'
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 "<stdin>", line 1, in <module>
IOError: [Errno 2] 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 "/home/fnngj/py_se/tryy.py", line 3, 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
现在只打印了一行具体错误信息。

异常的抛出机制:
1、如果在运行时发生异常,解释器会查找相应的处理语句(称为handler).
2、要是在当前函数里没有找到的话,它会将异常传递给上层的调用函数,看看那里能不能处理。
3、如果在最外层(全局“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()
        if len(line) == 0:
            break
        time.sleep(2)
        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 "tryy.py", line 18, in <module>
    time.sleep(2)
KeyboardInterrupt

  程序读poem.txt文件中每一行数据打印,但是我有意在每打印一行之前用time.sleep方法暂停2秒钟。这样做的原因是让程序运行得慢一些。在程序运行的时候,按Ctrl-c中断/取消程序。
  我们可以观察到KeyboardInterrupt异常被触发,程序退出。但是在程序退出之前,finally从句仍然被执行,把文件关闭。


到目前为止,我们只讨论了如何捕捉异常,那么如何抛出异常呢?

Raise抛出异常

 
使用raise来抛出一个异常:
tryr.py
#coding=utf-8
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[0] + s[1]
          print s[0] - s[1]
     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(5)
     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 = 3
            y = 2
      if x % y > 0:                               #如果大于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语句检测。
原文地址:https://www.cnblogs.com/timssd/p/4703609.html