6-3-异常对象

基于类的异常有如下特点:

  • 提供类型分类,对今后的修改有更好的支持。
  • 它们附加了状态信息。
  • 它们支持继承。

1. 异常:回到未来

1.1 编写异常类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class General(Exception): pass
class Specific1(General): pass
class Specific2(General): pass

def raiser0():
X = General()
raise X

def raiser1():
X = Specific1()
raise X

def raiser2():
X = Specific2()
raise X

for func in (raiser0, raiser1, raiser2):
try:
func()
except General:
import sys
print('caught:', sys.exc_info()[0])
caught: <class '__main__.General'>
caught: <class '__main__.Specific1'>
caught: <class '__main__.Specific2'>

2. 为什么使用类异常

把库的异常安排到类树中,有个共同的超类来包装整个类型。这样,用户只需列出共同的超类,来捕捉库的所有异常。

3. 内置 Exception 类

Python 把内置异常组织成层次,来支持各种捕捉模式。

**BaseException。**异常的顶级根类。这个类不能当作是由用户定义的类直接继承的(使用 Exception)。它提供了子类所继承的默认的打印和状态保持行为。
**Exception。**与应用相关的异常的顶层根超类。是所有其他内置异常的超类,除了系统推出事件类之外。
**ArithmeticError。**所有数值错误的超类。
**OverflowError。**识别特定的数值错误的子类。

3.1 默认打印和状态

内置异常还提供了默认打印显示和状态保持。传递给这些类的任何构造函数参数都会保存在实例的 args 元组属性中,并且当打印该实例的时候自动显示,对于用户定义的异常也是如此:

1
raise IndexError
---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

<ipython-input-3-55a00e7db5b5> in <module>()
----> 1 raise IndexError

IndexError: 
1
raise IndexError('spam')
---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

<ipython-input-4-53b7e456dbfa> in <module>()
----> 1 raise IndexError('spam')

IndexError: spam
1
2
I = IndexError('spam')
I.args
('spam',)

4. 定制打印显示

可以在类中定义两个字符串表示重载方法中的一个(__repr____str__),来返回想要为异常显示的字符串:

1
2
3
4
5
6
7
8
class MyBad(Exception):
def __str__(self):
return 'Always look on the bright side of life...'

try:
raise MyBad()
except MyBad as X:
print(X)
Always look on the bright side of life...
1
raise MyBad()
---------------------------------------------------------------------------

MyBad                                     Traceback (most recent call last)

<ipython-input-7-ff3b7d17d944> in <module>()
----> 1 raise MyBad()

MyBad: Always look on the bright side of life...

5. 定制数据和行为

5.1 提供异常细节

当引发一个异常的时候,可能会跨越任意的文件界限——触发异常的 raise 语句和捕获异常的 try 语句可能位于完全不同的模块文件中。在异常自身中传递额外的状态信息,这允许 try 语句更可靠地访问它。

1
2
3
4
5
6
7
8
9
10
11
12
class FormatError(Exception):
def __init__(self, line, file):
self.line = line
self.file = file

def parser():
raise FormatError(42, file='spam.txt')

try:
parser()
except FormatError as X:
print('Error at', X.file, X.line)
Error at spam.txt 42

5.2 提供异常方法

异常类也可以定义在处理器中调用的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 使用异常状态信息把错误记录到一个文件中
class FormatError(Exception):
logfile = 'formaterror.txt'
def __init__(self, line, file):
self.line = line
self.file = file

def logerror(self):
log = open(self.logfile, 'a')
print('Error at:', self.file, self.line, file=log)

def parser():
raise FormatError(40, 'spam.txt')

if __name__ == '__main__':
try:
parser()
except FormatError as exc:
exc.logerror()