异常
对异常的最好描述是: 它是因为程序出现了错误而在正常控制流以外采取的行为. 这个行为又分为两个阶段: 首先是引起异常发生的错误, 然后是检测(和采取可能的措施)阶段.
异常的检测和处理
try-except语句
try:
try_suite # watch for exceptions here 监控这里的异常
except Exception[, reason]:
except_suite # exception-handling code 异常处理代码
关键词: 忽略代码, 继续执行, 和向上移交
try 语句块中异常发生点后的剩余语句永远不会被执行. 一旦一个异常被引发, 就必须决定控制流下一步到达的位置. 剩余代码将被忽略,解释器将搜索处理器, 一旦找到,就开始执行处理器中的代码.如果没有找到合适的处理器,那么异常就向上移交给调用者去处理,这意味着堆栈框架立即回到之前的那个.
try 语句块中异常发生点后的剩余语句永远不会被执行. 一旦一个异常被引发, 就必须决定控制流下一步到达的位置. 剩余代码将被忽略,解释器将搜索处理器, 一旦找到,就开始执行处理器中的代码.如果没有找到合适的处理器,那么异常就向上移交给调用者去处理,这意味着堆栈框架立即回到之前的那个.
如果在上层调用者也没找到对应处理器,该异常会继续被向上移交, 直到找到合适处理器.如果到达最顶层仍然没有找到对应处理器,那么就认为这个异常是未处理的, Python 解释器会显示出跟踪返回消息, 然后退出。
带有多个except的try语句
<span style="font-size:10px;">try:
try_suite # watch for exceptions here 监控这里的异常
except Exception1[, reason1]:
suite_for_exception_Exception1
except Exception2[, reason2]:
suite_for_exception_Exception2</span>
处理多个异常的except语句
我们还可以在一个 except 子句里处理多个异常. except 语句在处理多个异常时要求异常被放在一个元组里:
try:
try_suite # watch for exceptions here 监控这里的异常
except (Exception1, Exception2)[, reason]:
suite_for_Exception1_and_Exception2
捕获所有异常
try:
try_suite # watch for exceptions here 监控这里的异常
except BaseException, e:
pass
不要尝试捕获所有异常,这样可能会忽略正确的错误。
else字句和finally字句
在 try 范围中没有异常被检测到时,执行 else 子句。
finally 子句是无论异常是否发生,是否捕捉都会执行的一段代码(例如关闭打开的文件),但是finally部分的字句可能会引发异常。
触发异常
程序员在编写 API 时也希望在遇到错误的输入时触发异常,为此,Python 提供了一种机制让程序员明确的触发异常:这就是 raise 语句。
raise语句
自定义异常类
#!/usr/bin/env python
'''
$Id$
myexc.py -- "my exceptions" demo which highlights user-created
exceptions. NOTE: this example does not currently work with
JPython as neither the errno nor tempfile modules have been
implemented, and also, the socket module is incomplete.
'''
# import all our needed modules
import os, socket, errno, types, tempfile
# create our a new NetworkError exception, derived from IOError
class NetworkError(IOError):
pass
# create our a new FileError exception, derived from IOError
class FileError(IOError):
pass
# updArgs --> tuple
def updArgs(args, newarg=None):
'''updArgs(args, newarg=None) -- if instance, grab each exception
instance argument and place them in a list; otherwise, just
convert given args sequence to a list for mutability; add
newarg if necessary; then convert the whole thing to a tuple.'''
if isinstance(args, IOError):
myargs = []
myargs.extend([arg for arg in args])
else:
myargs = list(args)
if newarg:
myargs.append(newarg)
return tuple(myargs)
# fileArgs --> tuple
def fileArgs(fn, mode, args):
'''fileArgs(fn, mode, args) -- similar to updArgs() except made
specifically for files; creates small permission string and
formats error to be similar to other IOError exceptions.'''
if args[0] == errno.EACCES and \
'access' in dir(os):
perms = ''
permd = { 'r': os.R_OK, 'w': os.W_OK, \
'x': os.X_OK }
pkeys = permd.keys()
pkeys.sort()
pkeys.reverse()
for eachPerm in 'rwx':
if os.access(fn, permd[eachPerm]):
perms = perms + eachPerm
else:
perms = perms + '-'
if isinstance(args, IOError):
myargs = []
myargs.extend([arg for arg in args])
else:
myargs = list(args)
myargs[1] = "'%s' %s (perms: '%s')" % \
(mode, myargs[1], perms)
myargs.append(args.filename)
else:
myargs = args
return tuple(myargs)
# myconnect() --> None (raises exception on error)
def myconnect(sock, host, port):
'''myconnect(sock, host, port) -- attempt to make a network connection
with the given socket and host-port pair; raises our new NetworkError
exception and collates error number and reason.'''
try:
sock.connect((host, port))
except socket.error, args:
myargs = updArgs(args) # convert inst to tuple
if len(myargs) == 1: # no #s on some errors
myargs = (errno.ENXIO, myargs[0])
raise NetworkError, \
updArgs(myargs, host + ':' + str(port))
# myopen() --> file object
def myopen(fn, mode='r'):
'''myopen(fn, mode) -- wrapper around the open() built-in function
such that we raise our new FileError exception on an error situation
and collate a set of FileError exception arguments to pass to the user'''
try:
fo = open(fn, mode)
except IOError, args:
print "IOError occur"
raise FileError, fileArgs(fn, mode, args)
return fo
# testfile() --> None
def testfile():
'''testfile() -- runs the file tester, setting a variety of test files
which should generate FileError exceptions'''
fn = tempfile.mktemp() #make temp file and path
f = open(fn, 'w')
f.close()
for eachTest in ((0, 'r'), (0100, 'r'), (0400, 'w'), (0500, 'w')):
try:
os.chmod(fn, eachTest[0])
f = myopen(fn, eachTest[1])
except FileError, args:
print "%s: %s" % \
(args.__class__.__name__, args)
else:
print fn, "opened ok... perms ignored"
f.close()
os.chmod(fn, 0777)
os.unlink(fn)
# testnet() --> None
def testnet():
'''testfile() -- runs the network tester, making various connections
which should generate NetworkError exceptions'''
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
for eachHost in ('127.0.0.1', 'www'):
try:
myconnect(s, eachHost, 80)
except NetworkError, args:
print "%s: %s" % (args.__class__.__name__, args)
else:
print "network connection successful to", `eachHost`
s.close()
# run tests if invoked as a script
if __name__ == '__main__':
testfile()
testnet()