【异常语句】
try/except: 捕捉由PYTHON自身或写程序过程中引发的异常并恢复
try/finally: 无论异常是否发生,执行清理行为
raise: 手动在代码中触发异常
assert: 有条件地在程序代码中触发异常
with/as PYTHON后续版本中实现环境管理器
【异常的角色】
下面是它最常见的几种角色
1. 错误处理
>>>可以在程序代码中捕捉和相应错误,或者忽略已发生的异常。
>>>如果忽略错误,PYTHON默认的异常处理行为将启动:停止程序,打印错误信息。
>>>如果不想启动这种默认行为,就用try语句来捕捉异常并从异常中恢复。
2. 事件通知
>>>异常也可用于发出有效状态的信号,而不需在程序间传递结果标志位。或者刻意对其进行测试
3. 特殊情况处理
>>>有时,发生了某种很罕见的情况,很难调整代码区处理。通常会在异常处理中处理,从而省去应对特殊情况的代码
4. 终止行为
>>>try/finally语句可确保一定会进行需要的结束运算,无论程序是否有异常
5. 非常规控制流程
>>>异常是一种高级的goto,它可以作为实现非常规的控制流程的基础。
>>>虽然反向跟踪并不是语言本身的一部分,但它能够通过PYTHON异常来实现,需要一些辅助逻辑来退回赋值语句
【新版本自定义类异常例子】
>>> class MyBad(Exception): pass
>>> def doomed(): raise MyBad
>>> try:
... doomed()
... except MyBad:
... print 'got bad'
...
got bad
【PYTHON整个异常控制流程】
1. 由PYTHON或程序触发的异常,可以忽略(打印错误信息),也可以由try语句进行扑捉。
2. try语句有两种逻辑格式:
一种是处理异常
另一种是执行最终的代码,而不管异常是否发生.
3. PYTHON的raise,assert可以按照需要触发异常
【try语句格式】
【默认行为例子】
def func(x,y):
return x / y
def test(x):
func(x,0)
test(1)
执行结果:
>>>
Traceback (most recent call last):
File "D:\python\test.py", line 7, in <module>
test(1)
File "D:\python\test.py", line 5, in test
func(x,0)
File "D:\python\test.py", line 2, in func
return x / y
ZeroDivisionError: integer division or modulo by zero
PYTHON没有捕捉的异常会向上传递到PYTHON进程的顶层,并执行PYTHON默认异常处理逻辑,也就是说,PYTHON终止执行中的程序,并打印标准错误信息。
【捕捉内置异常】
def func(x,y):
return x + y #会触发类型异常错误
try:
func([1,2,3],'abc')
except TypeError: #捕捉并恢复
print 'Hello,World!'
print 'resume here!' #程序继续执行
执行结果:
>>>
Hello,World!
resume here!
NOTE:
1. 一旦捕捉到异常,控制权会在捕捉的地方继续下去,没有直接的方式回到异常发生的地方.
2. 如果这里没有捕捉到异常,比如说,执行下面的语句
except ZeroDivisionError:
则后面的程序就会终止而不会执行
【try/finally语句例子】
try:
<statements> #首先运行可能触发异常的语句
finally:
<statements> #不管前面是否有异常,finally语句块都会执行
finally语句主要用于:文件关闭,服务器断开等
class MyError(Exception):
pass
def func(file):
raise MyError
f = open('data') #打开文件
try:
func(f) #手动触发异常
finally:
f.close() #总是会关闭文件
print 'file closed...'
【合并try的例子】
下面例子示范了四种常见场景,通过print语句说明其意义
第一种:异常触发并捕获
print '-' * 30,'\nEXCEPTION RAISED AND CAUGHT'
try:
x = 'spam'[99]
except IndexError:
print 'except run'
finally:
print 'finally run'
print 'after run'
第二种:无异常触发
print '-' * 30,'\nNO EXCEPTION RAISED'
try:
x = 'spam'[3]
except IndexError:
print 'except run'
finally:
print 'finally run'
print 'after run'
第三种:无异常触发,ELSE语句执行
print '-' * 30,'\nNO EXCEPTION RAISED, ELSE RUN'
try:
x = 'spam'[3]
except IndexError:
print 'except run'
else:
print 'else run'
finally:
print 'finally run'
print 'after run'
第四种:异常触发,但没有捕获
print '-' * 30,'\nEXCEPTION RAISED BUT NOT CAUGHT'
try:
x = 1 / 0
except IndexError:
print 'except run'
finally:
print 'finally run'
print 'after run'
执行结果:
------------------------------
EXCEPTION RAISED AND CAUGHT
except run
finally run
after run
------------------------------
NO EXCEPTION RAISED
finally run
after run
------------------------------
NO EXCEPTION RAISED, ELSE RUN
else run
finally run
after run
------------------------------
EXCEPTION RAISED BUT NOT CAUGHT
finally run
Traceback (most recent call last):
File "D:\python\test.py", line 34, in <module>
x = 1 / 0
ZeroDivisionError: integer division or modulo by zero
【raise语句】
要故意触发异常,请使用raise. 形式简单,使用方便.
格式一: raise <name> #手工触发一个异常
格式二: raise <name>, <data> #触发异常并传递额外的数据到捕获器
格式三: raise #重新触发,如果想把刚捕获的异常传递给另外一个处理器,必须用到
【raise简单例子】
class MyError: #定义MyError类,注意字符串不能用于捕获
print 'My Error class'
def func():
raise MyError #手工触发自定义异常类
try:
func() #尝试捕获异常
except MyError: #匹配/查找,触发的异常是否一致
print 'got myError' #如match,则处理异常
【利用raise传递额外的数据】
raise语句可以随异常一起传递额外的数据项给处理器使用。一般而言,额外数据可以向处理器传递关于异常的背景信息。例如:如果正在写数据文件分析器,可能会在遇到错误时引发语法错误异常,此外也传入一个对象,把行号和文件信息提供给处理器。
这是很有用的,因为异常引发时,也许会跨越任意的文件边界:触发异常的raise语句以及进行捕捉的try语句,也许位于完全不同的文件中,一般来说:无法把额外的细节存储在广域变量内,因为try语句可能不知道广域变量位于哪个文件中。和异常本身一起吧额外的数据传递进去,可让try语句读取时,更有把握。 就像函数的返回值:
每个异常都有这个额外的数据,如果没有刻意的传递什么时,就默认为特殊的None对象.
class MyException(Exception): pass
def raiser1():
raise MyException, 'Pass Extra Data to Raiser.'
def raiser2():
raise MyException
def tryer(func):
try:
func()
except MyException, extrainfo:
print 'got this', extrainfo
tryer(raiser1)
tryer(raiser2)
运行结果:
>>>
got this Pass Extra Data to Raiser.
got this
【利用raise传递异常】
raise语句不包括异常名称或额外值时,就是重新引发当前异常。如果需要捕捉和处理一个异常,又不希望异常在程序代码中死掉,一般就会使用这种方式.
>>> try:
... raise IndexError, 'spam'
... except IndexError:
... print 'raise pass exception to top cather!'
... raise
...
raise pass exception to top cather!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
IndexError: spam
通过这种方式执行raise时,会重新引发异常,并将其传递给更高层的处理器,或者顶层默认的处理器,也就是停止程序,打印标准错误消息。
【assert语句】
这是raise常见使用模式的语法简写,可视为带条件的raise语句。语句格式为:
assert <test>, <data> #<data>部分可选
比如下面例子:
如果断言成立的话,不会触发异常
>>> myStr = 'spam'
>>> assert len(myStr) > 1, 'The length of string is more than 1'
>>> assert range(4)==[0,1,2,3]
>>> assert 1 == 1
如果断言不成立的话,则触发AssertionError的异常
>>> assert len(myStr) > 10, 'The length of string is more than 1'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: The length of string is more than 1
所以其语法等价于:
if __debug__:
if not <test>:
raise AssertionError,<data>
【assert作用】
assert主要是收集约束条件,而不是错误或异常!assert语句是用于验证开发期间程序状况的。
显示时,其错误信息正文会自动包括源代码的行信息。以及列在assert语句中的值。如下例:
#File: asserter.py
def func(x):
assert x < 0, 'x must be negative!'
return x ** 2
执行结果:
>>> from asserter import *
>>> func(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "asserter.py", line 2, in func
assert x < 0, 'x must be negative!'
AssertionError: x must be negative!
牢记一点:assert都是用来收集用户定义的约束条件的,而不是捕捉内在的程序设计错误的。因为PYTHON会自动收集程序的设计错误,通常来说是没有必要写assert去捕捉超出索引值,类型不匹配以及除数为0之类的事情。比如说下面:
def func(x,y):
assert x !=0 #这是没有必要的,PYTHON会自动处理
return x / y #被除数为0的情况.
【with/as环境管理器】
从PYTHON2.6开始,引入的新的异常相关的语句: with以及可选的as分句。这个语句的设计是为了和环境管理器对象一起工作。
简而言之:with/as语句的设计是作为常见try/finally用法模式的替代方案。 就像try/finally语句,with/as语句也是用于定义必须执行的终止或清理行为,无论处理步骤中是否发生异常。和try/finally不同的是,with语句支持更丰富的基于对象的协议,可以为代码块定义支持进入或离开的动作。
PYTHON以环境管理器强化一些内置工具,例如,自动关闭打开的文件,以及对锁的自动上锁和开锁。程序员也可以用类编写自己的环境管理器。
【with/as用法】
因with/as是PYTHON2.6才开始使用的,所以2.5及之前的版本需要导入:
>>> from __future__ import with_statement
语句格式如下:
with experssion [as variable]: #as为可选
with-block
这里expression要返回一个对象,从而支持环境管理协议
如果选用as分句时,此对象也可返回一个值,将其赋值给变量名variable
NOTE:
1. variable并非赋值为experssion的结果。
2. expression的结果是支持环境协议的对象,而variable则是赋值为其他的东西
3. experssion返回的对象可在with-block开始前,先执行启动程序,并且在该代码完成后,执行终止程序代码,无论该代码块是否引发异常。
with open(r'data.txt') as myfile:
for line in myfile:
print line
或者其他支持环境管理的协议:
lock = threading.Lock()
with lock:
with-block
【PYTHON中常用异常处理测试模块】
def doStuff():
doFirstthing()
doSecondthing()
doLastthing()
def goodEnd(): pass
def badEnding(): pass
if __name__== '__main__':
try:
doStuff()
except:
badEnding()
else:
goodEnding()
finally:
file.close()
conn.close()
【PYTHON异常语句】
简单来说:
try: 是捕捉
raise: 是触发
assert: 是条件式引发
with: 是把代码块包装在环境管理器中,而从定义进入和离开的行为
【with/as实际例子】
【类异常特点】
和旧的字符串异常模型相比,类异常有如下特点
. 提供类型分类,对今后的修改有更好的支持:新增异常时,不需要在try语句中进行修改
. 提供了存储在try处理器中所使用的环境信息的合理地点:这样的话,可以拥有状态信息以及可调用的方法,并且可以通过实例进行读取
. 允许异常参与继承层次,从而获得共同的行为。例如:继承的显示方式可提供通用的错误信息的外观。
基于类的异常支持了程序的演进和较大系统,从这方面讲,它远优于基于字符串的异常.
【字符串异常】
PYTHON2.5之前的版本,还可以
>>> myexc = "My exception string"
>>> try:
... raise myexc
... except myexc:
... print 'caught'
caught
之后的版本,显示异常:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: exceptions must be old-style classes or derived from BaseException, not str
【基于类的异常】
字符串和类异常的主要区别在于,引发的异常在try语句中的except分句匹配时的方式不同。
. 前者是以简单对象识别来匹配的:引发的异常是由PYTHON的is测试来匹配except分句的
. 后者是由超类关系进行匹配:只要except分句列举了异常的类,或其任何超类名,引发的异常就会匹配该分句
当try语句的except分句列出一个超类时,就可以捕捉该超类的实例,以及类树中所有较低位置的子类的实例。结果就是类异常支持异常的层次架构:超类变成分类的名称,而子类变成了这个分类中的异常。except分句列出一个通用的异常超类,就可以捕捉整个分类中的各种异常:任何特定的子类都可匹配。
【类异常例子】
例1:
class MyException:
def __init__(self,value):
self.value = value
def __str__(self):
return 'self.value'
try:
raise MyException, 'My bad!'
except MyException, e:
print "My Exception occured, value:", e.value
#输出结果
>>>
>>>
My Exception occured, value: My bad!
例2:
class Super: pass
class Sub01(Super): pass
class Sub02(Super): pass
def raiser0():
X = Super()
raise X
def raiser1():
X = Sub01()
raise X
def raiser2():
X = Sub02()
raise X
for func in (raiser0,raiser1,raiser2):
try:
func()
except Super: #匹配父类及子类
import sys
print 'caught:',sys.exc_info()[0]
执行结果:
C:\>python classexc.py
>>>
caught: __main__.Super
caught: __main__.Sub01
caught: __main__.Sub02
NOTE:
1. sys.exc_info调用,这是一种抓取最近发生异常的常见方式
2. 引发基于类的异常,一定要有个实例
3. PYTHON官方文档之处,自定义类最后继承自Exception
class Super(Exception): pass
【内置Exception类】
1. 所有熟悉的异常(如:IndexError,SyntaxError)其实都是预定义的类,可以作为内置变量名,放在__builtin__模块中.
2. 以及作为标准库模块exceptions的属性。
3. PYTHON把内置异常组织成层次,来支持各种捕捉模式
Exception: 异常的顶层根超类
|
StandardError: 所有内置错误异常的超类
|
ArithmeticError: 所有数值错误的超类
|
OverflowError: 识别特定的数值错误的子类
查询办法:
>>> import exceptions
>>> help(exceptions)
>>> dir(exceptions)
【定义异常文本】
对于未被捕获的类异常,消息包含什么呢? 在默认的情况下,得到的是类的名称以及被抛出的实例对象。
>>> class MyBad: pass
...
>>> raise MyBad()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.MyBad: <__main__.MyBad instance at 0x000000000285A608>
上述显示不太美观,作为改进,可以用__repr__,__str__重载函数方法,来重写自己想要的默认异常结果:
>>> class MyBad:
... def __repr__(self):
... print 'Sorry,My mistake!'
...
>>> raise MyBad()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.MyBadSorry,My mistake!
NOTE:另外一种情况,如果我们的类继承自内置异常类,错误显示会发生微妙的改变,因为构造方法参数会自动存储并显示在消息中,如下:
>>> class MyBad(Exception): pass
...
>>> raise MyBad()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.MyBad
>>> class MyBad(Exception): pass
...
>>> raise MyBad('This','is','super','exception','test!')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.MyBad: ('This', 'is', 'super', 'exception', 'test!')
【类的额外数据传递】
分析数据文件的程序可能引发异常实例(填入有关错误的额外细节)从而发出格式错误的信号
class FormatError: #格式化错误
def __init__(self,line,file):
self.line = line
self.file = file
def parser():
#When error found
raise FormatError(42,file='spam.txt')
try:
parser()
except FormatError, X:
print 'Error at', X.line,X.file
在except分句中,变量X赋值为异常引发时所产生的实例。上述的传递异常的额外数据,用字符串的方式也可以实现,但是如果类有行为时,类这种方法可能更方便些
class FormatError:
def __init__(self,line,file):
self.line = line
self.file = file
def logerror(self):
log = open('formaterror.txt','a')
print >> log, 'Error at', self.file, self.line
def parser():
raise FormatError(40,'spam.txt')
try:
parser()
except FormatError, exc:
exc.logerror()
【raise语句的一般格式】
raise语句有5种形式,前两者是引发字符串异常,后两个是引发类异常,而最后一个是重新引发当前异常
raise string #匹配对象为string的异常
raise string,data #在上面的基础上再传递额外的数据
raise instance #如: raise instance.__class__.instance
raise class,instance #匹配该异常类及她的超类
raise #重新触发异常,如果需要传递任意的异常时,就有用处
比如说,要触发KeyError的异常可以用以下几种方式之一:
raise KeyError() #正常格式: 触发一个实例
raise KeyError,KeyError #类,实例: 使用实例
raise KeyError #类:一个实例将要产生
raise KeyError,'spam' #类,变量:一个实例将要产生
而下面的raise,则是将X赋值给了引发的KeyError实例对象
try: pass
except KeyError, X: pass
【PYTHON将不再使用基于字符串的异常】
Guido说:在未来PYTHON版本会消失。这样做的理由:
基于字符串的异常不支持分类、状态信息或行为继承,不像基于类的异常。在程序规模比较小时,还比较容易使用,一旦程序规模变大,就变得难以使用了。
【嵌套异常处理器】
try/except语句:
try/finally语句:
【try/except嵌套例子】
#File: exec.py
def action1():
print 1 + [] #通常的类型错误
def action2():
try:
action1()
except TypeError: #最近的找到的匹配错误
print 'inner error'
try:
action2()
except TypeError:
print 'outer error'
执行结果:
C:\>python exec.py
inner error
这里有两个激活的try语句,一个在action1内,一个在action2内。PYTHON会挑选并执行except最近的try,本例子中就是action1()中的try.
【语法嵌套化例子】
上面的代码给下面的等价
def action1():
print 1 + []
try:
try:
action1()
except TypeError:
print 'inner try'
except TypeError:
print 'outer try'
如果换成为try/finally,代码如下:
try:
try:
raise TypeError
finally:
print 'inner try'
finally:
print 'outer try'
执行结果:
>>>
inner try
outer try
Traceback (most recent call last):
File "D:\python\test.py", line 3, in <module>
raise TypeError
TypeError
下面是try/except/finally嵌套实现的代码及业务逻辑
def raiser1(): return
def raiser2(): raise EOFError
def raiser3(): raise TypeError
for func in (raiser1,raiser2,raiser3):
print '\n',func
try:
try:
func()
except TypeError:
print 'caught TypeError!'
finally:
print 'finally run'
执行结果如下:
>>>
<function raiser1 at 0x000000000256E748>
finally run
<function raiser2 at 0x0000000002DDB0B8>
finally run
Traceback (most recent call last):
File "D:\python\test.py", line 8, in <module>
func()
File "D:\python\test.py", line 2, in raiser2
def raiser2(): raise EOFError
EOFError
【异常不总是错误】
在PYTHON中错误都是异常,但异常不总是错误。比如对文件对象进行读取操作,文件末尾会有空字符,sys.stdin读取末尾的空字符串行会报EOFError的异常,这不是错误,是正常行为。除非放到try,并放到嵌套的循环内,如:
while 1:
try:
line = raw_input('Enter here:')
except EOFError:
break
else:
...
【函数信号条件和raise】
用户定义的异常也可引发非错误的情况。比如:搜索程序可以写成找到相符者引发异常,而不是为调用者返回状态标志来拦截。在下面的代码中,try/except/else处理器做的就是if/else返回值的测试工作
class Found(Exception): pass
def searcher():
if ...success...:
raise Found()
else:
return
try:
searcher()
except Found:
...success...
else:
...failure...
如果所有对象都是可能的有效返回值,就不可能以任何返回值来代表不寻常的情况。异常则提供了一种方式来传达结果讯息,而不使用返回值,如下例
class Failure(Exception): pass
def searcher():
if ...success...
return ...founditem...
else:
raise Failure()
try:
item = searcher()
except Failure:
...report...
else:
...use item here...
因为PYTHON核心是动态类型和多态的,通常更趋向于使用异常来发出这类情况的信号,而不是警示性的返回值。
【在try外进行调试】
可以利用异常处理器,取代PYTHON的默认顶层异常处理行为。在顶层代码中的外层try中包装整个程序,就可以捕捉任何程序执行时会发生的异常,因此可替代默认的程序终止行为。空的except分句会捕捉任意程序执行时所引发的而未被捕捉到的异常。要取得所发生的实际异常,可以从内置sys模块取出sys.exc_info函数返回的结果:
try:
...run program...
except:
import sys
print 'uncaught|',sys.exc_info()[0],sys.exc_info()[1]
这种结构在开发期间会经常使用,在错误发生时,仍保持程序处于激活状态:这样可以执行其他的测试,而不用重新开始。测试其他程序时,也会用到她。
【运行进程中的测试】import sys
log = open('testlog','a')
from testapi import moreTests,runNextTest,testName
def testdrive():
while moreTests():
try:
runNextTest()
except:
print >> log,'FAILED',testName(),sys.exc_info()[:2]
else:
print >> log,'PASSED',testName()
testdriver()
在这个例子中,模块testapi是抽象的。
在这里的testdriver函数会循环进行一组测试调用。因为测试案例中未被捕捉的异常,一般都会终止这个测试驱动程序,如果我们想在测试失败后让测试进程继续下去,就需要try中包装测试案例的调用。
空的except会捕捉由测试案例所产生的没有被捕获的异常,而其使用sys.exc_info把该异常记录到文件中。测试成功时,else分句就会执行。对于作为测试驱动运行在同一个进程的函数,模块,类,而进行测试的系统而言,这种形式固定的代码是很典型的。
更完整的测试框架:Doctest,PyUnit
【 sys.exc_info】sys.exc_info结果是获得最近引发的异常的最好方式。如果没有处理器正在处理,就返回包含三个None值的元祖
>>> import sys
>>> print sys.exc_info()
(None, None, None)
否则会返回(type,value和traceback)
log = open('log.txt','a')
try:
print 1 / 0
except ZeroDivisionError:
import sys
print >> log, sys.exc_info()
执行结果:
(<type 'exceptions.ZeroDivisionError'>, ZeroDivisionError('integer division or modulo by zero',), <traceback object at 0x0000000002DE12C8>)
. type是正在处理的异常的异常类型
. value是异常参数(她的关联或raise的第二参数,如果异常类型为类对象,就一定是类实例)
. traceback是一个traceback对象,代表异常最初发生时所调用的堆栈
【与异常相关技巧:应该包装什么】
这其实是设计的问题,不在语言范围本身,而且实际运用时,就会更明显,列出一些简要的原则:
. 经常会失败的运算一般都应该包装在try语句中
>>>例如:和系统状态衔接的运算(文件开启、套接字调用等)就是try的主要候选者
. 简单的脚本,如希望这类运算失败时终止程序,而不是被捕捉或被忽略,就用放try里面
. 应该在try/finally中实现终止动作,从而包装它们的执行。无论异常是否发生,如文件句柄,数据库连接关闭
. 偶尔,把对大型函数的调用包装在单个try语句中,而不是让函数本身零散放在若干的try语句中,这样更方便
【捕捉太多:避免空except】
空except分句会捕捉try代码块中代码执行时所引发的每一个异常。写很容易,有时候也能得到我们想要的结果,但这样做的话可能会拦截到高层的try处理器所期待的时间。如下例子中异常处理器,会捕捉到每个到达的异常并使其停止,无论是否有另外一个处理在等待该事件.
def func():
try:
raise IndexError
except:
print 'inner try' #任何异常都会被捕获
try:
func()
except IndexError: #实际需要在此捕捉的异常
print 'outer try'
这类代码可能会捕捉无关的系统异常。例如:内存错误、一般程序错误、迭代停止以及系统退出等,都会在PYTHON中引发异常。这类异常通常是不应该被拦截的。例如:sys.exit(statuscode)调用提前终止,这实际上是引发内置的SystemExit异常来终止程序,使try/finally可以离开前执行,而程序的特殊类型可拦截该事件,因此,try带except时,可能会不知不觉阻止重要的结束。
import sys
def func():
sys.exit(40)
try:
func()
except:
print 'got it'
print 'continue...'
运行结果:
>>>
got it
continue...
更坏的情况是:
空except会捕捉一般程序设计错误,但这类错误多数情况下应该让其通过
dictionary = {'a':1,'b':2}
try:
x = ditctionary['a'] #拼写错误的情况
except:
x = None #建设我们获得了KeyError
字典名拼写错了,但用这种方式捕捉,PYTHON会为未定义的变量名引发NameError,但处理器会默默的捕捉并忽略这个异常。如果这件事发生在离读取值的使用很远的地方,就会变成一项很难的调试任务!
所以原则就是:尽量让处理器具体化,空except分句很方便,但是很容易出错。例如上面的例子,最好写成except KeyError,意图明确,避免拦截无关的事件.
【捕捉过少:使用基于类的分类】
另一方面,捕获器也不应该太过具体化,比如下面:
下面的处理器是把myerror1和myerror2看作是正常情况,并把其他的一切视为错误。如果未来增加了myerror3,就会视为错误,除非更新异常列表
try:
...
except myerror1,myerror2:
...
很好的替代方案是:将所有的异常放置在一个超类中
class super(Exception): pass
class myerror1(super): pass
class myerror2(super): pass
class myerror3(super): pass
try:
...
except super:
...
到时候有更新的话,只需要加一句: class myerror3(super): pass就可以了。
基于异常类的层次分类,可以让代码更好管理与维护,特别是大型系统。异常规则也应该是整体设计的一部分。
【字符串异常匹配是通过同一性而不是通过值】
字符串比较短的情况
>>> ex1 = 'hello'
>>> ex2 = 'hello'
>>> ex1 == ex2, ex1 is ex2
(True, True)
字符串比较长的情况
>>> ex1 = 'This is a long sentence!'
>>> ex2 = 'This is a long sentence!'
>>> ex1 == ex2, ex1 is ex2
(True, False)
NOTE;字符串足够长的话,会突破PYTHON的字符串的内部缓存机制,变成一个全新的对象。
因此,如果是同一对象的话,字符串捕捉的异常会和except匹配
>>>try:
raise ex1
except ex1:
print 'got it'
got it
如果不是同一对象的话,下面的则会失败
try:
raise ex1
except ex2:
print 'got it'
在比如,下面是成功的
try:
raise 'spam'
except 'spam':
print 'got it'
而这样确实失败的
try:
raise 'spam'*8
except 'spam'*8
print 'got it'
好在:新的PYTHON的版本会逐渐淘汰字符串异常格式
【PYTHON工具集】
一般而言,PYTHON提供了一个有层次的工具集
内置工具:
像字符串、列表以及字典这些内置类型,会让编程更迅速
PYTHON扩展
就更重要的任务来说,可以编写自己的函数、模块以及类,来扩展PYTHON
已编译的扩展
PYTHON也可以使用C/C++这样的外部语言编写的模块进行扩展