异常处理
try…except语句用于异常处理。
>>> while True:
... try:
... x = int(input("Please enter a number: "))
... break
... except ValueError:
... print("Oops! That was no valid number. Try again...")
可以有多个except字句,也可以同时指定多种异常
... except (RuntimeError, TypeError, NameError):
... pass
异常继承匹配
父类可以捕获子类异常
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")
打印输出B,C,D。如果except倒序为B,C,D则打印输出B,B,B。
匹配任意异常
最后的except字句可以省略异常类型,实现捕获任意异常的功能
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise #reraise this exception
else子句
可以附加一个else子句在try…except语句的最后(finally之前),else是可选的,但是必须位于所有except之后,表示如果try中的语句没有异常产生,则else中的内容被执行。
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except OSError:
print('cannot open', arg)
else:
print(arg, 'has', len(f.readlines()), 'lines')
f.close()
finally子句
可选的finally字句必须位于try语句的最后,但是和else不同,finally之前可以没有except和else,无论try子句中是否有异常抛出,在离开try语句前finally里的内容都会被执行。
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print("division by zero!")
... else:
... print("result is", result)
... finally:
... print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
如果try子句或者之后的except或者else子句有没有被捕获的异常产生,finally执行后,该异常会被自动再次抛出。通过break,continue,return在离开try语句前,finally也会被执行,如果finally中有return,那么finally中return的值会被返回,而非try,except,else中return的值。
finally子句通常用于清理工作,无论资源的使用情况是否成功,最后都释放掉资源。
异常变量
except语句可以指定异常变量,捕获具体的异常实例对象,异常实例对象的args属性存储着和异常相关的数据。
>>> try:
... raise Exception('spam', 'eggs')
... except Exception as inst:
... print(type(inst)) # the exception instance
... print(inst.args) # arguments stored in .args
... print(inst) # __str__ allows args to be printed directly,
... # but may be overridden in exception subclasses
... x, y = inst.args # unpack args
... print('x =', x)
... print('y =', y)
...
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs
抛出异常
raise关键字用于抛出异常
>>> raise NameError('HiThere')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: HiThere
raise之后可以是异常实例对象或者是异常类型,如果是异常类型,该类型的默认构造器被自动调用用于实例化一个异常对象
raise ValueError # shorthand for 'raise ValueError()'
except字句中,重抛出被捕获的异常,可以简单的使用raise
>>> try:
... raise NameError('HiThere')
... except NameError:
... print('An exception flew by!')
... raise
...
An exception flew by!Traceback (most recent call last):
File "<stdin>", line 2, in <module>NameError: HiThere
自定义异常
通过直接或非直接继承Exception类,可以定义自己的异常类型
class Error(Exception):
"""Base class for exceptions in this module."""
pass
class InputError(Error):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
class TransitionError(Error):
"""Raised when an operation attempts a state transition that's not
allowed.
Attributes:
previous -- state at beginning of transition
next -- attempted new state
message -- explanation of why the specific transition is not allowed
"""
def __init__(self, previous, next, message):
self.previous = previous
self.next = next
self.message = message
和内建的标准异常类型类似,一般异常类型都以Error结尾,每个不同的模块都有自己的异常基类,该模块中可能出现的具体异常类型则由该异常基类导出。
预定义了清理动作的对象
一些对象需要在不再被需要时执行特定的清理动作,可以用try…exception…finally语句确保这些清理动作得到执行。
不过更加简洁高效安全的做法是对这类对象使用with…as语句声明,with…as…将在其中的执行体执行完毕,或者中途抛出异常时确保其预定义的清理动作一定得到调用,支持此类用法的对象都有close方法,其中预定义了该对象的清理操作。
with open("myfile.txt") as f:
for line in f:
print(line, end="")