标准异常

眼熟一下

  • BaseException-所有异常的基类
  • SystemExit-揭示其请求退出
  • KeyboardInterrupt-用户中断执行(通常是输入^c)
  • Exception-常规错误的基类
  • StopIteration-迭代器没有更多的值
  • GeneratoExit-生成器generator发生异常来通知退出
  • StandardError-所有的内建标准异常的基类
  • ArithmeticError-所有数值计算错误的基类
  • FloatingPointError-浮点计算错误
  • OverflowError-数值运算超过最大限制
  • ZeroDivisionError-除(或取模)零(所有数据类型)
  • AssertionError-断言语句失败
  • AttributeError-对象没有这个属性
  • EOFError-没有内建输入到达EOF标记
  • EnvironmentError-操作系统错误的基类
  • IOError-输入/输出操作失败
  • OSError-操作系统错误
  • WindowsError-系统调用失败
  • ImportError-导入模块/对象失败
  • LookupError-无效数据查询的基类
  • IndexError-序列中没有此索引
  • KeyError-映射中没有这个键
  • MenoryError-内存溢出错误(对于python解释器来说不是致命的)
  • NameError-为声明/初始化对象(没有属性)
  • UnboundLocalError-访问未初始化的本地变量
  • ReferenceError-弱引用试图访问已经垃圾回收了的对象
  • RuntimeError-一般的运行时错误
  • NotimeplementedError-尚未实现的方法
  • SyntaxError-python语法错误
  • IndentationError-缩进错误
  • TabError-Tab和空格混用
  • SystemError-一般的解释器系统错误
  • TypeError-对类型无效的操作
  • ValueError-传入无效的参数
  • UnicodeError-Unicode相关的错误
  • UnicodeDecodeError-Unicode解码时错误
  • UnicodeEncodeError-Unicode编码时错误
  • UnicodeTranslateError-Unicode转换时错误
  • Warning-警告的基类
  • DeprecationWarning-关于被弃用的特征的警告
  • FutureWarning-关于狗仔将来语义会有改变的警告
  • OverflowWarning-旧的关于自动提升为长整型的警告
  • PendingDeprecationWarning-关于特性将会被废弃的警告
  • RuntimeWarning-可疑的运行时行为的警告
  • SyntaxWarning-可疑的语法的警告
  • UserWarning-用户代码生成的警告

什么是异常

异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。一般情况下,在python无法正常处理程序时就会发生一个异常。异常是python对象,表示一个错误。
当python脚本发生异常时,我们需要捕获处理它,否则程序会终止执行。

异常处理

捕获异常可以使用try/except语句
try/except语句用来检测try语句块中的错误,从而让except语句捕获以异常信息并处理。
如果你不想再异常发生时结束你的程序,只需在try里面捕获它。
语法:
简单的try...except...else语法:

try
<语句>    #运行别的代码
except <名字>:
<语句>    #如果在try部分引发了name异常
except <名字>,<数据>:
<语句>    #如果引发了name异常,获取附加的数据
else:
<语句>    #如果没有异常发生

try的工作原理:当开始一个try语句后,python就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否发生异常。

  • 如果try后的语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过整个try语句(除非在处理异常时又引发新的异常)
  • 如果try后的语句里发生了异常,却没有匹配到except子句,异常将被递交到上层的try,或者在程序的最上层(这样就结束程序,并打印默认的出错信息)
  • 如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。

使用except而不带任何异常类型

你可以不带任何异常类型使用except,实例:
try:
    正常操作
    ················
except:
    发生异常,执行这块代码
    ················
else:
    如果没有异常执行这块代码
以上方法的try-except语句可以捕获所有发生的异常,但不能识别具体发生的异常信息。

使用except而带多种异常类型

可以使用同一个except处理多个异常信息,异常信息放在元组中

try:
    正常操作
    ···············
except (Exception1[,Exception2[,...ExceptionN]]]):
    ···············
else:
`    如果没有异常执行这块代码

try-finally语句

try-finally语句无论是否发生异常都将执行最后的代码。

try:
<语句>
finally:
<语句>    #退出try时总会执行
raise

实例1:

fh = open("testfile", "r")
try:
    fh.write("这是一个测试文件,用于测试异常!!")
finally:
    print ("关闭文件")
    fh.close()
print('end')

实例2:

try:
    fh = open("testfile", "r")
    try:
        fh.write("这是一个测试文件,用于测试异常!!")
    finally:
        print ("关闭文件")
        fh.close()
except IOError:
    print ("Error: 没有找到文件或读取文件失败")
print('end')

这两个实例进行对比。
try-finally语句不管是否异常都会执行finally语句但是,因为没有except语句,即异常捕获处理语句,程序依然会停止
实例1输出:

Traceback (most recent call last):
  File "C:/Users/24201/Desktop/python学习/test.py", line 4, in <module>
    fh.write("这是一个测试文件,用于测试异常!!")
io.UnsupportedOperation: not writable
关闭文件

并没有执行try-finally语句外的print
但是,实例2中存在except异常处理语句,只要异常在可控范围内,则程序不会崩溃:

关闭文件
Error: 没有找到文件或读取文件失败
end

except处理了内层try-finally未处理的Error,致使程序不至于不能继续执行而崩溃。

其作用机理,try代码块中抛出一个异常时,立即执行finally代码块。finally执行完毕后,异常被再次触发,并执行except代码块。
同时try-finally可以与try-except-else一起用

抛出异常

使用raise语句抛出一个指定的异常
语法:
raise[Exception[,arg[,traceback]]]
实例:

x=10
if x>5:
    raise Exception('x不能大于5.x的值为:{}'.format(x))
print('woc')

输出:

Traceback (most recent call last):
  File "C:/Users/24201/Desktop/python学习/test.py", line 3, in <module>
    raise Exception('x不能大于5.x的值为:{}'.format(x))
Exception: x不能大于5.x的值为:10

raise唯一的一个参数制定了要被抛出的异常,它必须是一个异常的实例或者是异常的类(也就是Exception的子类)。如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的raise语句就可以再次把它抛出。
并且从输出可以看出,raise抛出的异常确实可以达到中断程序的特性。

用户自定义异常

用户可以通过创建一个新的异常类来拥有自己的异常,异常类继承自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)
raise MyError('oops!')

输出:

Traceback (most recent call last):
  File "C:/Users/24201/Desktop/python学习/test.py", line 13, in <module>
    raise MyError('oops!')
__main__.MyError: 'oops!'
My exception occurred, value: 4

在这个例子中,类Exception默认的int()被覆盖。当创建一个模块有可能抛出多种不同的异常时,一种通常的做法是为这个包建立一个基础异常类,然后基于这个基础类为不同的错误情况创建不同的子类。
实例:

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

定义清理行为

try语句还有另外一可选的子句,它定义了无论在任何情况选都会执行的清理行为,例:

try:
    raise KeyboardInterrupt
finally:
    print('goodbye world!')

以上例子不管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:',result)
    finally:
        print('executing finally clause')
divide(1,2)
divide(2,0)
devide('1','2')

输出:

result: 0.5
executing finally clause
division by zero!
executing finally clause
Traceback (most recent call last):
  File "C:/Users/24201/Desktop/python学习/test.py", line 12, in <module>
    devide('1','2')
NameError: name 'devide' is not defined

预定义的清理行为

一些对象定义了标准的清理行为,无论系统是否成功的使用了它,一旦不需要它了,那么这个标准的清理行为就会执行。

for line in open("myfile.txt"):
    print(line, end="")

以上这段代码的问题里,当执行完毕后,文件会保持打开状态,并没有被关闭。
关键词with语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法

temp = os.open('test_text.txt', os.O_RDWR | os.O_CREAT)
temp_file = os.fdopen(temp, 'r')
print(str(temp_file.read()))
os.close(temp)

简化

with open('test_text.txt', 'r') as f:
    print(f.read())

以上这段代码执行完毕后,就算在处理过程中出问题了,文件f总是会关闭

异常的参数

实例:

# 定义函数
def temp_convert(var):
    try:
        return int(var)
    except (ValueError) as Argument:
        print ("参数没有包含数字\n", Argument)
# 调用函数
temp_convert("xyz");

输出:

参数没有包含数字
 invalid literal for int() with base 10: 'xyz'

assert断言

python的assert用于判断一个表达式,在表达式条件为false的时候触发异常。断言可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况,例如我们的代码只能在linux系统下运行,可以先判断当前系统是否符合条件。
语法:

assert expression

等价于

if not expression:
    raise AssertionError

assert后面可以紧跟参数:

assert expression[,arguments]

等价于:

if not expression:
    raise AssertionError(arguments)

以下为assert的使用实例:

>>> assert True     # 条件为 true 正常执行
>>> assert False    # 条件为 false 触发异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError
>>> assert 1==1    # 条件为 true 正常执行
>>> assert 1==2    # 条件为 false 触发异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

>>> assert 1==2, '1 不等于 2'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: 1 不等于 2
>>>