1.理解异常以及错误处理。
2.会用try语句对可能引发异常的代码进行定界。
3.学会raise异常。
4.会用except子句指定异常处理程序。
5.会用finally子句释放资源。
6.理解python异常类层次结构。
7.理解python的跟踪机制。
8.会创建程序员自定义的异常。
异常处理
问题可能发生,但发生得并不频繁。这种特殊事件通常是一个错误(例如除以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;
分享到:
2012-10-25 22:41
浏览 2447
评论