Python之异常处理
一、什么是异常处理
定义:异常处理就是我们在写Python时,经常看到的报错信息,例如;NameError TypeError ValueError等,这些都是异常。
异常是一个事件,改事件会在程序执行过程中发生,影响程序的正常执行,一般情况下,在python中无法处理程序时就会发生异常,异常时Python的一个对象,表示一个错误,当Python脚本发生异常时,我们需要捕获并处理异常,否则程序就会终止执行。
二、异常处理
当Python脚本出现异常的时候我们怎么处理那?
就如我们使用的工具出现了一点毛病,我们可以想办法修理好它,程序也是一样,之前的前辈们经过不断的积累与思考,创造了很多好得方法处理程序中出现的异常,本章我们就讲一下使用try语句处理异常。
首先我们来说一下try语句的语法:
try语句与except 相结合使用,此语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理,如果不想在发生异常时结束程序,只需要在try语句中捕获异常即可
try:
<代码块>
except <异常名字>
print(‘语句’)
实例如下:
def func():
try:
a = x/y
print('a=',a)
return a
eccept Exception:
print('程序出现异常,异常信息:被除数为0')
三、抛出异常
在Python中使用raise语句抛出一个指定的异常,我们可以使用类或实例参数调用raise语句引发异常。
实例如下:
class EvaException(BaseException):
def __init__(self,msg):
self.msg=msg
def __str__(self):
return self.msg
try:
raise EvaException('类型错误')
except EvaException as e:
print(e)
四、捕捉多个异常
我们前面说了怎么处理一个异常的情况,如果涉及到多个,我们该怎么处理那?
在Python中支持一个try/except语句处理多个异常,语法如下:
try: <语句> except <异常名字>: print(‘异常说明’) except <异常名字>: print(‘异常说明’) try语句的工作方式如下:
首次执行try中语句块,如果没有发生异常,则忽略except中的字句,try语句中的代码块执行后结束。如果try语句中的代码块出现异常,try中的剩余语句则会被忽略,
如果异常和eccept中的异常名字一直,相应的except语句就会被执行。如果一个异常也没有匹配,这个异常就会传递给上层的try语句中,一个语句可能包含第一个except语句,
分别处理不同的异常,但是最多只有一个分支会执行。
try:
#a
#1/0
dic = {1:2}
dic[3]
except NameError:
print('名字没有定义,报错了')
except ZeroDivisionError:
print('0不能当做除数,报错了')
except KeyError:
print('没有这个key')
五、异常中else
我们如果程序执行完异常后还想做其他的事情怎么办?
这时我们就可以用到异常中的else了,具体语法如下:
try:
<语句>
except <异常名字> :
<语句>
except <异常名字>:
<语句>
else:
<语句> #(try语句中没有异常后执行此段代码)
如果在try语句中执行没有发生异常,就会执行else语句,使用else语句比把所有语句都放在try字句里面更好,这样可以避免一些意想不到的而except有没有捕获到的异常:
def func(x,y):
try:
a = x/y
except :
print('Error,happened')
else:
print('It went as execpt')
func(2,1)
六、用户自定义异常
你可以通过创建一个新的exception类来拥有自己的异常。异常应该继承自 Exception 类,或者直接继承,或者间接继承,例如:
class MyError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
try:
raise MyError(2*2)
except MyError as e:
print('My exception occurred, value:', e.value)
My exception occurred, value: 4
raise MyError('oops!')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
main__.MyError: 'oops!'
在这个例子中,类 Exception 默认的 __init__() 被覆盖。
当创建一个模块有可能抛出多种不同的异常时,一种通常的做法是为这个包建立一个基础异常类,然后基于这个基础类为不同的错误情况创建不同的子类:
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"结尾,就跟标准的异常命名一样。
七、定义清理行为(finally语句)
try 语句还有另外一个可选的子句,它定义了无论在任何情况下都会执行的清理行为。 例如:
>>> try:
... raise KeyboardInterrupt
... finally:
... print('Goodbye, world!')
...
Goodbye, world!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
KeyboardInterrupt
以上例子不管 try 子句里面有没有发生异常,finally 子句都会执行。
如果一个异常在 try 子句里(或者在 except 和 else 子句里)被抛出,而又没有任何的 except 把它截住,那么这个异常会在 finally 子句执行后再次被抛出。
下面是一个更加复杂的例子(在同一个 try 语句里包含 except 和 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 ?
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
预定义的清理行为
一些对象定义了标准的清理行为,无论系统是否成功的使用了它,一旦不需要它了,那么这个标准的清理行为就会执行。
这面这个例子展示了尝试打开一个文件,然后把内容打印到屏幕上:
for line in open("myfile.txt"):
print(line, end="")
以上这段代码的问题是,当执行完毕后,文件会保持打开状态,并没有被关闭。
关键词 with 语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法:
with open("myfile.txt") as f:
for line in f:
print(line, end="")
以上这段代码执行完毕后,就算在处理过程中出问题了,文件 f 总是会关闭。
python标准异常
异常名称 | 描述 |
---|---|
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
Exception | 常规错误的基类 |
StopIteration |
迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
ImportError | 导入模块/对象失败 |
LookupError | 无效数据查询的基类 |
IndexError | 序列中没有此索引(index) |
KeyError | 映射中没有这个键 |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 尚未实现的方法 |
SyntaxError | Python 语法错误 |
IndentationError | 缩进错误 |
TabError | Tab 和空格混用 |
SystemError | 一般的解释器系统错误 |
TypeError | 对类型无效的操作 |
ValueError | 传入无效的参数 |
UnicodeError | Unicode 相关的错误 |
UnicodeDecodeError | Unicode 解码时的错误 |
UnicodeEncodeError | Unicode 编码时错误 |
UnicodeTranslateError | Unicode 转换时错误 |
Warning | 警告的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
FutureWarning | 关于构造将来语义会有改变的警告 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
SyntaxWarning | 可疑的语法的警告 |
UserWarning | 用户代码生成的警告 |