本章将学习创建和引发自定义的异常,以及处理异常的各种方法。
8.1 什么是异常
程序运行中的错误或者不期望发生的事情就是异常,为了防止这样的事件你可以使用大量的条件语句,但是这样做的成本会非常高并且没效率。
在Python中,用异常对象(exception object)来表示异常。如果异常对象未被处理或者捕捉,程序就会使用回溯(Traceback,一种错误信息)来终止程序。事实上每个异常都是一些异常类的实例,异常类的实例在不同情况被引发,并且都能够被捕捉到后进行错误处理,而不至于程序运行失败。
8.2 按自己的方式出错
8.2.1 raise语句
有很多内建的异常类,详细介绍可以查询Python的文档“Built-in Exception”相关部分。
可以使用dir列出exceptions模块内容:
>>> import exceptions
>>> dir(exceptions)
['ArithmeticError', 'AssertionError', ...]
下面是使用内建异常类的简单例子:
>>> raise Exception
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception
>>> raise Exception('hyperdriver overload')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: hyperdriver overload
8.2.2 自定义异常类
如果内建异常类不能满足程序的需求,可以自定义异常类。只需要保证自定义异常类是直接或者间接从Exception类继承的即可:
class SomeCustomException(Expception): pass
8.3 捕捉异常
假如有一个要让用户输入两个数来整除的程序是这样的:
n = input('Enter your first number:')
m = input('Enter your second number:')
print n / m
$ python class.py
Enter your first number:10
Enter your second number:0
Traceback (most recent call last):
File "class.py", line 3, in <module>
print n / m
ZeroDivisionError: integer division or modulo by zero
可以通过捕捉异常来处理它们:
try:
n = input('Enter your first number:')
m = input('Enter your second number:')
print n / m
except ZeroDivisionError:
print 'The second number can not be zero!'
$ python class.py
Enter your first number:10
Enter your second number:0
The second number can not be zero!
我们虽然捕捉了异常并打印了信息,实际上却可以不处理它,而让它继续传递。
如下是一个有 "屏蔽" ZeroDivisionError错误的代码示例。当muffled=Fasle时,会直接打印错误信息;否则异常会传递给上层调用者。
class MuffledCalculator:
muffled = False
def calc(self, expr):
try:
return eval(expr)
except ZeroDivisionError:
if self.muffled:
print 'Division by zero is illegal.'
else:
raise
>>> c = MuffledCalculator()
>>> c.calc("12/0")
Traceback (most recent call last):
File "class.py", line 12, in <module>
c.calc("12/0")
File "class.py", line 5, in calc
return eval(expr)
File "<string>", line 1, in <module>
>>> c.muffled = true
>>> c.calc("12/0")
ZeroDivisionError: integer division or modulo by zero
8.4 不止一个except子句
在前面的例子中,还会有别情况,比如用户输入的如果是字符串,直接进行除法运算可能导致TypeError的异常,这时候就可以用多个except子句:
try:
n = input('Enter your first number:')
m = input('Enter your second number:')
print n / m
except ZeroDivisionError:
print 'The second number can not be zero!'
except TypeError:
print 'That was not number, is it?'
8.5 用一个块捕捉两个异常
上节中的多种异常情况如果不需要进行单独处理,能够更加简洁地用元组表示:
try:
n = input('Enter your first number:')
m = input('Enter your second number:')
print n / m
except (ZeroDivisionError, TypeError, NameError):
print 'Your number was bongus!'
当然只是打印错误信息并没有什么意义,另一个方案就是要求用户输入合理的数字直到可以进行运算位为止。
8.6 捕捉对象
如果不想终止程序运行,又想在except子句中获取错误信息,可以直接访问异常对象:
try:
n = input('Enter your first number:')
m = input('Enter your second number:')
print n / m
except (ZeroDivisionError, TypeError, NameError), e:
print e
$ python class.py
Enter your first number:10
Enter your second number:0
integer division or modulo by zero
8.7 真正的全捕捉
总有一些用户操作会躲过try/except的检查,比如在上面的例子中,用户什么也不输入直接回车:
$ python class.py
Enter your first number:
Traceback (most recent call last):
File "class.py", line 2, in <module>
n = input('Enter your first number:')
File "<string>", line 0
^
SyntaxError: unexpected EOF while parsing
要Python对所有异常全部进行捕捉可以在except的子句中什么异常类也不写:
try:
n = input('Enter your first number:')
m = input('Enter your second number:')
print n / m
except:
print 'Something wrong happen...'
8.8 万事大吉
在try/except子句中,如果发生了exception会走except分支,如果没有发生exception,还可以新增一个else分支。如下示例:
try:
print 'A Simple Task'
except:
print 'What? Something went wrong!'
else:
print 'Ah... I went as planed'
$ python class.py
A Simple Task
Ah... I went as planed
8.9 最后
除了else子句外,还有finally子句可以用来做一些清理工作(finally子句无论是否发生异常都会执行):
try:
1/o
except NameError:
print 'Unknown variable!'
else:
print 'That wents well'
finally:
print 'Clean up'
$ python class.py
Unknown variable!
Clean up
8.10 异常和函数
如果异常在函数中没有被处理,就会被传播至函数调用的地方,如此层层往上直到被处理。
8.11 异常之禅
在某些时候try/except和if/else子句可以实现同样的功能,但是if/else自然性和可读性差些,应该养成尽可能的多使用try/except的习惯。
“在做一件事情的过程中去处理可能出现的错误,而不是在做这件事情之前做大量的检查”。
8.12 小结
- 异常对象
- 警告[注:该章压根就没提到警告好么]
- 引发异常
- 自定义异常类
- 捕捉异常
- else子句
- 异常和函数
8.12.1 本章的新函数
略
8.12.2 接下来学习什么
略
网友评论