1、异常简介
从软件方面来说,错误是语法或是逻辑上的,当python检测到一个错误时,解释器就会指出当前流已经无法继续执行下去,这时候就出现了异常。异常分为两个阶段:首先是引起异常发生的错误,然后是检测和采取可能的措施。常见异常有NameError、ZeroDivisionError、SyntaxError、IndexError、KeyError、IOError、AttributeError、ValueError、TypeError等。所有的标准/内建异常都是从根异常派生的,目前,有3个直接从BaseException派生的异常子类:SystemExit,KeyboardInterrupt和Exception。其它的所有的内建异常都是Exception的子类。
2、异常检测及处理
异常可以通过try语句来检测,有两种主要形式:try-except和try-finally。前者可以添加一个可选的else子句来处理没有检测到异常的情况。一个try语句可以对应一个或多个except语句,但只能对应一个finally子句,except用来捕获并处理异常,可以处理多个异常,也可以指定可选的异常参数(将会是一个包含来自异常的代码的诊断信息的类实例,异常参数自身会组成一个元组,并存储为类实例的属性),要避免裸except(会捕获所有异常,没有机会保存异常发生的原因,虽然可以通过sys.exc_info()获得,但不推荐,如果想捕获所有异常,可以在except中使用BaseException类,而Exception类不包括KeyboardInterrupt和SystemExit),finally无论发生错误与否都会执行。try-except-finally是个复合语句。try检测到异常时,try语句块中的剩余代码是不会执行的,异常会延着堆栈向上提交,直到找到合适的异常处理器,如果到达最顶层仍然没有找到对应的处理器,python解释器会显示出跟踪返回消息,然后退出。
Python用异常对象(exception object)表示异常情况,遇到错误后,会引发异常。如果异常对象并未被处理或捕捉,程序就会用所谓的回溯(Traceback,一种错误信息)终止执行。
try
语句的工作原理如下。
- 首先,执行 try 子句 (
try
和except
关键字之间的(多行)语句)。 - 如果没有异常发生,则跳过 except 子句 并完成
try
语句的执行。 - 如果在执行try 子句时发生了异常,则跳过该子句中剩下的部分。然后,如果异常的类型和
except
关键字后面的异常匹配,则执行 except 子句 ,然后继续执行try
语句之后的代码。 - 如果发生的异常和 except 子句中指定的异常不匹配,则将其传递到外部的
try
语句中;如果没有找到处理程序,则它是一个 未处理异常,执行将停止并显示如上所示的消息。
try:
try_suite
except Exception1[, reason1]:
suite_for_exception_ Exception1
except Exception2[, reason2]:
suite_for_exception_ Exception2
except (Exception3, Exception4)[, reason3_4]:
suite_for_exceptions_ Exception3_and_Exception4
except (Exc5[, Exc6[, ... ExcN]])[, reason]:
suite_for_exceptions_ Exc5_to_ExcN
else:
suite_for_no_exception
finally:
suite_always_run
可同时捕捉多个异常,可捕捉异常对象,可忽略异常类型以捕捉所有异常
>>> try:
x = int(input('input x:'))
y = int(input('input y:'))
print('x/y = ',x/y)
except ZeroDivisionError: #捕捉除0异常
print("ZeroDivision")
except (TypeError,ValueError) as e: #捕捉多个异常,并将异常对象输出
print(e)
except: #捕捉其余类型异常
print("it's still wrong")
input x:12
input y:0
ZeroDivision
>>> try:
x = int(input('input x:'))
y = int(input('input y:'))
print('x/y = ',x/y)
except ZeroDivisionError: #捕捉除0异常
print("ZeroDivision")
except (TypeError,ValueError) as e: #捕捉多个异常,并将异常对象输出
print(e)
except: #捕捉其余类型异常
print("it's still wrong")
input x:12
input y:y
invalid literal for int() with base 10: 'y'
try/except 可以加上 else 语句,实现在没有异常时执行什么
>>> try:
x = int(input('input x:'))
y = int(input('input y:'))
print('x/y = ',x/y)
except ZeroDivisionError: #捕捉除0异常
print("ZeroDivision")
except (TypeError,ValueError) as e: #捕捉多个异常
print(e)
except: #捕捉其余类型异常
print("it's still wrong")
else: #没有异常时执行
print('it work well')
input x:12
input y:3
x/y = 4.0
it work well
2. 捕捉异常
为了处理异常,我们使用try...except
把可能发生错误的语句放在try模块里,用except来处理异常。
except可以处理一个专门的异常,也可以处理一组圆括号中的异常,如果except后没有指定异常,则默认处理所有的异常。
每一个try,都必须至少有一个except
在python的异常中,有一个万能异常:Exception,他可以捕获任意异常
s1 = 'hello'
try:
int(s1)
except Exception,e:
print e
程序时需要考虑到try代码块中可能出现的多个异常,可以这样写:
s1 = 'hello'
try:
int(s1)
except IndexError,e:
print e
except KeyError,e:
print e
except ValueError,e:
print e
异常的简单结构和复杂结构
try:
pass
except Exception as e: #python2 中还可以这样写:except Exception,e
pass
try
语句子句形式表
except
: 捕获所有异常
except
name: 只捕获特定的异常
except
name,value: 捕获异常和它的附加数据(将异常的信息保存到value,)
except
(name1,name2): 捕获任何列出的异常
else
: 如果没有异常
finally
: 总是执行
先定义特殊提醒的异常,最后定义Exception,来确保程序正常运行。
先特殊,后万能
s1 = 'hello'
try:
int(s1)
except KeyError,e:
print '键错误'
except IndexError,e:
print '索引错误'
except Exception, e:
print '错误'
①.捕捉多个异常
在一个except语句只捕捉其后声明的异常类型,如果可能会抛出的是其他类型的异常就需要再增加一个except语句了,或者也可以指定一个更通用的异常类型比如:Exception,如下:
# -- coding: utf-8 --
try:
print 2/'0'
except ZeroDivisionError:
print '除数不能为0'
except Exception:
print '其他类型异常'
为了捕获多个异常,除了声明多个except语句之外,还可以在一个except语句之后将多个异常作为元组列出来即可:
# -- coding: utf-8 --
try:
print 2/'0'
except (ZeroDivisionError,Exception):
print '发生了一个异常'
②.获取异常信息
每个异常都会有一些异常信息,一般情况下我们应该把这些异常信息记录下来:
# -- coding: utf-8 --
try:
print 2/'0'
except (ZeroDivisionError,Exception) as e:
# unsupported operand type(s) for /: 'int' and 'str'
print e
3.自定义异常:
Python中也可以自定义自己的特殊类型的异常,只需要要从Exception类继承(直接或间接)即可,继承于 Exception 的类如下:
class myException(Exception):pass
class WupeiqiException(Exception):
def __init__(self, msg):
self.message = msg
def __str__(self):
return self.message
try:
raise WupeiqiException('我的异常')
except WupeiqiException,e:
print e
4.抛出异常和传递异常:
Python中的raise 关键字用于引发一个异常,基本上和C#和Java中的throw关键字相同。
>>> def division(x,y):
if y == 0 :
raise ZeroDivisionError('The zero is not allow')
return x/y
>>> try:
division(1,0)
except ZeroDivisionError as e:
print(e)
The zero is not allow
一般来说,raise关键字后面抛出的异常越详细越好,Python在exceptions模块内建了很多的异常类型,通过使用dir函数来查看exceptions中的异常类型,如下:
import exceptions
# ['ArithmeticError', 'AssertionError'.....]
print dir(exceptions)
传递异常,即捕捉到了异常,但是又想重新引发它(传递异常),可以使用不带参数的raise语句即可:
# -- coding: utf-8 --
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
主动触发异常
raise Exception('messages') 可以自定义报错信息
a=2
if a > 1:
raise ValueError('值大于1')
raise 触发异常
try:
raise Exception('错误了。。。')
except Exception,e:
print e
5.finally 语句
不管是否出现异常,最后都会执行finally的语句块内容,用于清理工作
所以,你可以在 finally 语句中关闭文件,这样就确保了文件能正常关闭
finally子句和try子句联合使用但是和except语句不同,finally不管try子句内部是否有异常发生,都会执行finally子句内的代码。所有一般情况下,finally自己常常用于关闭文件或者在Socket中。
>>> try:
x = int(input('input x:'))
y = int(input('input y:'))
print('x/y = ',x/y)
except ZeroDivisionError: #捕捉除0异常
print("ZeroDivision")
except (TypeError,ValueError) as e: #捕捉多个异常
print(e)
except: #捕捉其余类型异常
print("it's still wrong")
else: #没有异常时执行
print('it work well')
finally: #不管是否有异常都会执行
print("Cleaning up")
input x:12
input y:3
x/y = 4.0
it work well
Cleaning up
异常抛出之后,如果没有被接收,那么程序会抛给它的上一层,比如函数调用的地方,要是还是没有接收,那继续抛出,如果程序最后都没有处理这个异常,那它就丢给操作系统了 -- 你的程序崩溃了,这点和C++一样的。
注意:你可以使用except语句或者finally语句,但是两者不能同时使用。else语句也不能与finally语句同时使用
在else块是不需要try:块的代码的保护。
6.python标准异常
在 Python 中,所有异常必须为一个派生自 BaseException 的类的实例。 通过子类化创建的两个不相关异常类永远是不等效的,既使它们具有相同的名称。
下列异常主要被用作其他异常的基类。
BaseException: 所有异常的基类
Exception(重点掌握)
所有内置的非系统退出类异常都派生自此类。 所有用户自定义异常也应当没打算自此类。
ArithmeticError
此基类用于派生针对各种算术类错误而引发的内置异常: OverflowError, ZeroDivisionError, FloatingPointError。
BufferError
当与 缓冲区 相关的操作无法执行时将被引发。
LookupError
此基类用于派生当映射或序列所使用的键或索引无效时引发的异常: IndexError, KeyError
内置异常的层次结构
BaseException 所有异常的基类 +-- SystemExit 解释器请求退出 +-- KeyboardInterrupt 用户中断执行(通常是输入^C) +-- GeneratorExit 生成器(generator)发生异常来通知退出 +-- Exception 常规错误的基类 +-- StopIteration 迭代器没有更多值 +-- StopAsyncIteration 必须通过异步迭代器对象的__anext__()方法引发以停止迭代 +-- ArithmeticError 所有数值计算错误的基类 | +-- FloatingPointError 浮点计算错误 | +-- OverflowError 数值运算超出最大限制 | +-- ZeroDivisionError 除(或取模)零 (所有数据类型 +-- AssertionError 断言语句失败 +-- AttributeError 对象没有这个属性 +-- BufferError 与缓冲区相关的操作时引发 +-- EOFError 没有内建输入,到达EOF 标记 +-- ImportError 导入失败 | +-- ModuleNotFoundError 找不到模块 +-- LookupError 无效数据查询的基类 | +-- IndexError 序列中没有此索引(index) | +-- KeyError 映射中没有这个键 +-- MemoryError 内存溢出错误 +-- NameError 未声明、初始化对象 | +-- UnboundLocalError 访问未初始化的本地变量 +-- OSError 操作系统错误, | +-- BlockingIOError 操作将阻塞对象设置为非阻塞操作 | +-- ChildProcessError 子进程上的操作失败 | +-- ConnectionError 与连接相关的异常的基类 | | +-- BrokenPipeError 在已关闭写入的套接字上写入 | | +-- ConnectionAbortedError 连接尝试被对等方中止 | | +-- ConnectionRefusedError 连接尝试被对等方拒绝 | | +-- ConnectionResetError 连接由对等方重置 | +-- FileExistsError 创建已存在的文件或目录 | +-- FileNotFoundError 请求不存在的文件或目录 | +-- InterruptedError 系统调用被输入信号中断 | +-- IsADirectoryError 在目录上请求文件操作 | +-- NotADirectoryError 在不是目录的事物上请求目录操作 | +-- PermissionError 在没有访问权限的情况下运行操作 | +-- ProcessLookupError 进程不存在 | +-- TimeoutError 系统函数在系统级别超时 +-- ReferenceError 弱引用试图访问已经垃圾回收了的对象 +-- RuntimeError 一般的运行时错误 | +-- NotImplementedError 尚未实现的方法 | +-- RecursionError 解释器检测到超出最大递归深度 +-- SyntaxError Python 语法错误 | +-- IndentationError 缩进错误 | +-- TabError Tab 和空格混用 +-- SystemError 一般的解释器系统错误 +-- TypeError 对类型无效的操作 +-- ValueError 传入无效的参数 | +-- UnicodeError Unicode 相关的错误 | +-- UnicodeDecodeError Unicode 解码时的错误 | +-- UnicodeEncodeError Unicode 编码时错误 | +-- UnicodeTranslateError Unicode 转换时错误 +-- Warning 警告的基类 +-- DeprecationWarning 关于被弃用的特征的警告 +-- PendingDeprecationWarning 关于构造将来语义会有改变的警告 +-- RuntimeWarning 可疑的运行行为的警告 +-- SyntaxWarning 可疑的语法的警告 +-- UserWarning 用户代码生成的警告 +-- FutureWarning 有关已弃用功能的警告的基类 +-- ImportWarning 模块导入时可能出错的警告的基类 +-- UnicodeWarning 与Unicode相关的警告的基类 +-- BytesWarning bytes和bytearray相关的警告的基类 +-- ResourceWarning 与资源使用相关的警告的基类
异常名称 | 描述 |
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
Exception | 常规错误的基类 |
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
SystemExit | Python 解释器请求退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
ImportError | 导入模块/对象失败 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
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 | 用户代码生成的警告 |