`

Python异常处理

阅读更多

1.理解异常以及错误处理。
2.会用try语句对可能引发异常的代码进行定界。
3.学会raise异常。
4.会用except子句指定异常处理程序。
5.会用finally子句释放资源。
6.理解python异常类层次结构。
7.理解python的跟踪机制。
8.会创建程序员自定义的异常。

异常处理<Exception Handling)。"异常"是程序执行间发生的一个“特殊事件”。之所以称为“异常”,是因为尽管
问题可能发生,但发生得并不频繁。这种特殊事件通常是一个错误(例如除以0,或者对两个不兼容的类型求和);
但有时,特殊事件可能是别的情况(例如for循环终止)。通过异常处理,应用程序能处理(或解决)异常。许多
时候,进行异常处理的程序可继续执行,好象没有发生过问题。.......
     
     python中异常处理的样式以及细节基于Modula-3语言创始人的工作,它类似c#和java中的机制。
     程序通常会在执行期间请求和释放“资源”(比如磁盘文件)。通常,这些资源的供应有限,或者
     一次只能供一个程序使用。针对这个问题,我们将演示异常处理机制中相应的那一部分功能,既
     让一个程序使用资源,然后保证该程序能释放在月微秒年 ,以供其他程序使用。
    
    
     1。引发异常。

     要想引发异常,最简单的形式就是输入关键字raise,后跟要印发的异常的名称。异常名称标识出具体的类;
     python异常是那些类的对象。执行raise语句时,python会创建指定的异常类的一个对象。raise语句还可指
     定对异常对象进行初始化的对象。为此,请在异常类的名称后添加一个逗号以及指定的参数(或者由参数构
     成的一个元祖)。程序可根据异常对象的属性来获得与异常有关的更多信息。raise语句具有多种形式。
     ......
    
     2。异常处理
    
     程序逻辑经常要检测各种条件,
    
     执行一个任务
     如果上一个任务未能正确执行
         执行错误处理
     执行下一个任务
     如果上一个任务未能正确执行
        执行错误处理
     ...
    
     伪代码首先执行一个任务,再检测该任务是否正确执行。如果不是,就执行错误处理。
     否则,伪代码将继续下一个任务。尽管这种形式的错误处理也许行的通,但将程序逻辑
     和错误处理逻辑混合到一起,会使用程序难以阅读、修改、维护和调试--尤其是在大型
     应用程序中。事实上,如果存在许多发生频率并不高的潜在问题,将程序逻辑和错误处
     理混在一起会妨碍程序性能,因为程序必须不断测试附加条件,才能判断出是否能执行
     下一个任务。
         通过异常处理,程序员可将异常处理代码从程序的执行流程中分离出来。这样,程
     序结构会变得更加清楚,而且更容易修改。程序员可自行决定对那些异常进行处理。可
     选择处理所有类型的异常、特性类型的所有异常,或者一组相关类型的所有异常。这样
     的灵活性减少了错误被忽视的可能,所以增强了程序的可靠性。
    
         [[[[[程序员必须将异常处理策略考虑到软件项目中]]]]]]
        
         Example:
         ########Simple exception handing example########
           
         number1 = raw_input("Enter numerator:")
         number2 = raw_input("Enter denominator:")
        
         try:
           number1 = float(number1)
           number2 = float(number2)
           result = number1/number2
          
         except ValueError:
           print "You must enter two numbers"
        
         except ZeroDivisionError:
           print "Attempted to divide by zero"
        
         else:
           print "%.3f/%.3f = %.3f" %(number1,number2,result)
     
   
       3.Python的Exception层次结构
      
       python中的几个异常类。所有异常都从基类Exception继承,而且都在exceptions模块中定义。
       python自动将所有异常异常名称放在内建命名空间中,所以程序不必导入exceptions模块即可
       使用异常。python定义了从Exception继承的4个主要的类,包括SystemExit,StopIteration,
       Warning以及StandardError。其中,一旦引发而且没有捕捉SystemExit异常,程序执行就会终止。
       如果交互式会话遇到一个未被捕捉的SystemExit异常,会话就会终止。python使用StopIteration
       异常来判断一个for循环何时抵达序列末尾。Warning异常指出python的一个特定元素将来可能改变。
       例如,假定一个python2.2程序中使用了名为yield的一个变量,那么python会印发一个warning异常
       ,因此在phtyhon未来的该本中,以将yield定义为关键字。StandardError则是所有python“错误”异常
       (比如ValueError和ZeroDivsionError)的一个基类。
      
       Exception+
       |
       -----SystemExit[没有捕捉到该异常,程序直接停止]
       |
       -----StopIteration[判断一个for循环何时抵达序列末尾]
       |
       -----Warning[警告]
       |
       -----StandradError[所有错误异常的基类]
      
      
       对于任何python,都可以用以下语句显示该结构:
       ------------------------------
       | import exceptions          |
       | print exceptions.__doc__   |
       ------------------------------      
      
       但是如果并不清楚异常发生了什么使用:    
       -------------------
       |except Exception:|
       -------------------
      
      
       4.finally子句
      
       程序经常动态地(也就是在执行时)请求和释放资源。例如,从硬盘上读取一个文件的程序会
       请求打开那个文件。如果请求成功,就能读取文件内容。操作系统通常会阻止多个程序同时操作同
       一个文件。因此,当程序结束处理文件时,程序通常会关闭文件(也就是释放资源),以便其他程
       序能使用这个文件。关闭文件有助于避免"资源泄露"(即文件资源无法给其他程序使用,因为原来使
       用该文件的程序一直没有关闭)。获得特定类型资源(如文件)的程序必须将资源明确还给系统,以
       避免资源泄露。
      
          在c和c++等语言中,程序员要自己负责动态内存管理,一种最常见的资源泄露是”内存泄露“。
       如果程序分配(获取)了内存,但在不需要之后没有解释分配(回收),就会发生这种情况。不过在
       python中,这通常不是一个问题,因为解释器会对现在正在执行的程序不需要的内存进行”垃圾回收“。
       但是在python中有可能发生其他类型的资源泄露(比如前面提到的未关闭的文件)。
      
           对于要求明确释放的大多数资源来说,往往存在一些与资源处理相关的异常。例如,一个文件处理
           程序可能在处理期间引发IOError异常。因此,文件处理代码通常放在一个try suite中。无论程序
           是否成功处理文件,一旦不需要文件,都应将其关闭。
          
           假定程序将所有资源请求和释放代码都放在一个try suite中。如果没有发生异常,try suite会
           正常执行并释放资源。但是,如果发生异常,try suite会在资源释放代码执行之前”过期“。
           虽然可在except处理程序中复制所有资源放代码,但这样会使用代码难以修改和维护。
          
           python异常处理机制提供了finally子句,只要程序控制进入了响应的try suite,就必须会这个字句
           (无论try suite是成功执行,还是发生异常)。所以,对于在相应try suite中获取和处理的资源,
           finally suite是放置资源回收代码的理想地点。如果try suite成功执行,finally suite会在try
           suite终止后立即执行。如果在try suite中发生异常,那么在导致异常的那一行之后,会立即执行
           finally suite。然后,由下一个封闭的try语句(如果有的话)来处理异常。
          
        ######### Using finally clauses#######
        def doNotRaiseException():      
            try:
             print "In doNotRaiseException."
            finally:
              print "Finally exceuted in doNotRaiseException"
            print "End of doNotRaiseException"
           
         def raiseExceptionDoNotCatch():
            try:
             print "In raiseExceptionDoNotCatch"
             raise Exception
            finally:
              print "Finally executed in raiseExceptionDoNotCatch"
         print "Will never reach this point"
        
         print "Calling doNotRaiseException"
         doNotRaiseException()
        
         print "\nCalling raiseExceptionDoNotCatch"
        
         try:
           raiseExceptionDoNotCatch()
         except Exception:
           print "Caught exception from raiseExceptionDoNotCath"+\
           "in main program."
           
           
         ------------------------------------------------------------------------------
         |常见变成错误:在finally suite中引发异常是非常危险的。执行finally suite时。  |
         |假如一个未被捕捉的异常正在等候处理,而finally suite又引发一个新的,未被该   |
         |suite捕捉的异常,那么第一个异常就会丢失,新异常则传递给下一个封闭的try语句。|
         ------------------------------------------------------------------------------
        
         ------------------------------------------------------------------------------
         |如果try语句指定了一个finally子句,那么即使try suite由一个return语句终止,   |
         | finally子句的suite也会执行执行完之后,才论到通过return返回调用代码。       |
         ------------------------------------------------------------------------------
                
       ......

       6.Exception对象和跟踪
      
       从Exception类派生的异常数据类型可用0个或多个参数创建。这些参数常常用于为一个引发的异常格式化错误
       提示消息。只要python为了响应一个raise语句而创建一个异常对象,就会将来自raise语句的任何参数放到异
       常对象args属性中。
      
           发生异常时,python能”记住“引发的异常以及程序的当前状态。python还维护着traceback(跟踪)对象,
           其中含有异常发生时与函数调用堆栈有关的信息。记住,异常可能还在一系列嵌套较深的函数调用中引发。
           程序调用每个函数时,python 会在”函数调用堆栈“的起始处插入函数名,一旦异常被引发,python会搜索
           到一个响应的异常处理程序。如果当前函数中没有异常处理程序,或者python抵达主程序为止,这一查找
           合适的异常处理程序的过程就称为”堆栈辗转开解“(Stack Unwinding)。解释器一方面维护着与放置于
           堆栈中的函数有关的信息,另外方面也维护着已从堆栈中”辗转开解"的函数的有关的信息。
          
           #####################
           import traceback

      def function1():
         function2()

      def function2():
          function3()

      def function3():
         try:
            raise Exception,"An exception as occurred"
         except Exception:
            print "Caught exception in funtions3.Reraising...\n"
            raise #reraise most recent exception
      try:
         function1()
        except Exception,exception:
         print "Exception carght in mian program."
         print "\nException arguments:",exception.args
         print "\nException message:",exception
         print "\nTraceback:"
          traceback.print_exc()
   

          
           程序堆栈如下:
           function3(顶部)
           function2
           function1
           主程序
          
         换言之,最后一个调用的函数(function3)位于顶部,而主程序位于底部。function3的第16行引发
         一个Exception,并将"An exception has occurred"作为参数传递。为响应raise语句,Python使
         用指定的参数,创建一个Exception对象。except子句捕捉异常,并将第一个打印出消息。第2行使
         用一个空的raise语句“重新引发”异常。重新引发一个异常,通常意味着except处理程序只对异常执
         行了局部处理,现在要将异常传回调用者(目前是function2),以便进一步处理。在本例中,
         function3在不指定异常名称的前提下,使用关键字raise来重新引发最近引发过的一个异常。
        
         -----------------------------------------------------------------------
         |软件工程知识:假如一个函数能处理特定类型的异常,就放手让函数去处理它|
         |不要将异常传到程序的另一个区域。                                    |
         -----------------------------------------------------------------------
        
         接着,function3终止,因为重新印发的异常未在函数主体中捕获。所以,控制权会返回当初调用
         function3的语句(或者调用堆栈中的上一个函数,即function2)。这样会将function3从函数调用
         堆栈中删除(或称“辗转开解”),造成函数终止。与此同时,python会创建一个traceback对象,用
         它维护来有关函数调用的信息。
         控制权返回function2,解释器查明第10行不在一个try suite中。所以,异常无法在function2中捕捉,
         这导致function2终止,而且function2也从函数调用堆栈中“展转开解”,并创建另一个traceback对象
         (代表当前的辗转开解级别),并将控制权返回function1中的第7行。同样的事情再度发生。第7行不在
         一个try suite中,异常无法在function1中捕捉。这导致函数终止,并从调用堆栈中“辗转开解”。与此
         同时,创建另一个traceback对象,并使控制权返回至主程序的第24行。由于第24行在try suite中,所以
         主程序的try suite会立即“过期”,由第28+行的except处理程序捕捉异常。
        
         ....
         #######################################################################################
         #  说白了就是根据堆栈顺序,如果有异常,捕捉到响应suite即可。不用考虑是否函数体or区域  #
         #######################################################################################
        
        
         测试和调试提示 :阅读traceback报告时,请从下到上顺序,先读错误消息。然后,向上阅读trace
         剩余的部分,查找报告中的第一个行号。通常,这就是导致异常的位置。
        
        
         7。程序自定义异常类
        
         程序员通常可用Python层次结构中现有的异常类来标明程序中发生的异常。但在某些情况下,也可新
         建自己的异常类型,使其与程序中发生的问题 严格对应。这种“程序员自定义异常类”应直接或间接
         继承于Exception类。
        
         良好的变成习惯:使每类问题都与一个命名得体的异常类关联,使程序结构清晰易读。
        
         ###########Demonstating a programmer-defined exception class####
        
         import math
        
         class negativeNumberError(ArithmeticError):
         """Attempted improper operration on nagative number."""
           pass
         def squareRoot(number):
          if number<0:
           raise NegativeNumberError,\"Square root of negative number not permitted"
          return math.sqrt(nmber)
         while 1:
          try:
           userValue = float(raw_input("\nPlease enter a number:"))
           print squareRoot(userValue)
          
          except ValueError:
           print "The entered value is not a number"
         
          except NegativeNumberError,exception:
           print exception
          else:
           break;

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics