首页 > 脚本语言 > python > 实例浅谈之二Python自定义异常
2015
07-24

实例浅谈之二Python自定义异常

一、问题

 

Python中标准异常集包含的内容已经相当广泛,但有时开发中还须创建自己的异常,比如在特定的标准异常和模块异常中添加额外的信息。
本例中两个异常都与IOError有关,IOError是一个用于输入/输出的通用异常,可能在无效的文件访问或其他形式的通信中触发。

二、解决

 

1、创建自定义异常代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/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:
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()

程序自定义了两个新的异常类FileError与NetworkError,基类都是IOError,也重新实现了两个诊断版的函数open()[myopen()]和socket.connect([myconnect()],同时包含了一个在直接运行文件时执行的测试函数[test()]。

2、运行结果图

(centos6.5下运行结果:)

实例浅谈之二Python自定义异常 - 第1张  | 大话运维
myconnect()仅仅是简单的对套接字的函数conect()进行包装,当网络连接失败时提供一个IOError类型的异常,和一般的socket.error不一样,还提供给程序员主机名和端口号。当失败发生时,错误号和错误字符很有帮助,但是如果结合更精确的主机-端口会更有帮助,因为这一对可能是由某个数据库或名称服务动态生成或重新获得。这些值由connect()加入。另一种情形是无法找到主机,socket.error异常没有直接提供的错误号;为了遵循IOError协议,提供了一个错误号-错误字符串对;查找最接近的错误号,选用的是ENXIO。
myopen()封装了已经存在的一些代码,这里用的是open()函数,仅仅捕捉IOError异常。所有的其他都忽略并传给下一层(因为没有与它们相关的处理器)。一旦捕捉到IOError就引发自定义的异常并通过 fileArgs()返回值来定制参数。
上述分别是linux下使用不同的用户运行的结果,root用户拥有操作文件的所有权限。

最后编辑:
作者:saunix
大型互联网公司linux系统运维攻城狮,专门担当消防员

留下一个回复