十一、异常

一、异常解决

异常定义:Python 中,程序在执行的过程中产生的错误称为异常,如列表索引越界、打开不存在的文件等。

二、捕获异常

2.1 捕获简单异常

(1) 捕获异常 try…except…

try:
    print('-----test--1---')
    open('123.txt','r')
    print('-----test--2---')
except IOError:
    pass

(2)捕获多个异常

#coding=utf-8
try:
    print('-----test--1---')
    open('123.txt','r') # 如果123.txt文件不存在,那么会产生 IOError 异常
    print('-----test--2---')
    print(num)# 如果num变量没有定义,那么会产生 NameError 异常

except (IOError,NameError): 
    #如果想通过一次except捕获到多个异常可以用一个元组的方式
    print('产生错误了')

(3)捕获异常的描述as

#coding=utf-8
try:
    print('-----test--1---')
    open('123.txt','r') # 如果123.txt文件不存在,那么会产生 IOError 异常
    print('-----test--2---')
    print(num)# 如果num变量没有定义,那么会产生 NameError 异常

except Exception as result: 
    #如果想通过一次ex
    print(result)

exceptì吾句定义了一个 Exception(所有异常类的父类)的对象 result ,用于接收异常处理对象 打印result 可以输出异常信息,因为程序已经捕获到异常信息,所以不会再出现因为异常而退出的情况

(4)如果没有捕获到异常,那么就执行else中的事情

#coding=utf-8
try:
    print('-----test--1---')
    open('123.txt','r') # 如果123.txt文件不存在,那么会产生 IOError 异常
    print('-----test--2---')
    print(num)# 如果num变量没有定义,那么会产生 NameError 异常

except Exception as result: 
    #如果想通过一次ex
    print(result)
else:
	print('没有捕获到异常')

(5)终止行为finally

无论异常是否产生都要执行,常用于释放资源。

try:
   while True:
         content = f.readline()
         if len(content) == 0:
             break
         time.sleep(2)
         print(content)
 except:
     #如果在读取文件的过程中,产生了异常,那么就会捕获到
   print('捕获到异常')
 finally:
     f.close()
     print('关闭文件')

在程序退出之前,finally从句仍然被执行,把文件关闭。

  • else和finally必须写在except之后,finally需要写在最后,在没有except时else不能和try配合使用,否则会发生语法错误。

三、抛出异常

3.1 使用raise抛出异常

(1)使用类名引发异常
 ralse语句指定异常的类名时,会创建该类的实例对象,然后引发异常。

raise IndexError

(2)使用异常类的实例引发异常
 通过指定创建异常类的实例,直接使用该实例对象来引发异常。

index = IndexError()
raise 

(3)传递异常
 不带任何参数的 raise 吾句 ,可以再次引发刚刚发生过的异常 ,作用就是向外传递异常。

#coding=utf-8
try:
    print('-----test--1---')
    open('123.txt','r') # 如果123.txt文件不存在,那么会产生 IOError 异常
    print('-----test--2---')
    print(num)# 如果num变量没有定义,那么会产生 NameError 异常

except (IOError,NameError): 
    #如果想通过一次except捕获到多个异常可以用一个元组的方式
    print('产生错误了')
    raise

(4)指定异常的描述信息

>>> raise IndexError('索引下标超出范围')
Traceback (most recent call last):
  File "", line 1, in <module>
IndexError: 索引下标超出范围

(5)异常引发异常
 如果要在异常中抛出另外一个异常,可以使用raise-from语句实现。

>>> try:
...     namber
... except Exception as exception:
...     raise IndexError('索引下标超出范围') from exception
...
Traceback (most recent call last):
  File "", line 2, in <module>
NameError: name 'namber' is not defined

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "", line 4, in <module>
IndexError: 索引下标超出范围

(6)捕获所有的异常

try:
     namber
except Exception as exception:
     print(exception)

3.2 使用assert

 assert 语句又称作断言,指的是期望用户满足指定的条件 当用户定义的约束条件不满足的时候,它会触发 AssertionError 异常,所以 assert 语句可以当作条件式的 ralse 语句 。

assert 逻辑表达式,data    # data可选

以上等同于:

a = 0
if not a!=0:
	raise AssertionError(data)

程序实例:

>>> a = 0
>>> assert a!=0, 'a的值不能为0'
Traceback (most recent call last):
  File "", line 1, in <module>
AssertionError: a的值不能为0

assert 语句用来收集用户定义的约束条件,而不是捕捉内在的程序设计错误 因为 Python会自行收集程序的设计错误, 会在遇见错误时自动引发异常。

四、自定义异常

class ShortInputException(Exception):
    '''自定义的异常类'''
    def __init__(self, length, atleast):
        #super().__init__()
        self.length = length
        self.atleast = atleast

def main():
    try:
        s = input('请输入 --> ')
        if len(s) < 3:
            # raise引发一个你定义的异常
            raise ShortInputException(len(s), 3)
    except ShortInputException as result:#x这个变量被绑定到了错误的实例
        print('ShortInputException: 输入的长度是 %d,长度至少应是 %d'% (result.length, result.atleast))
    else:
        print('没有异常发生.')

main()

五、预定义清理

 之前在介绍 finally 语句时,说过 finally 语句用于释放资源,如关闭文件等 除了在 finally语句中手动释放资源以外,还可以使用 with 语句预定义清理操作,即无论资源在使用过程中是否发生异常,都会执行释放资源的操作,比如文件使用后自动关闭。

5.1 with 语句

with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的"清理"操作,释放资源。

with 文表达式 [as 资源对象]:
	对象的操作

上述语法格式表示的含义如下

  • 上下文表达式:返回一个上下文管理器对象。若指定了 as 子句,该对象并不赋值给资源对象,而是将上下文管理器的__enter__()方法的返回值赋值给资源对象。
  • 资源对象:可以是单个变量,也可以是元组
  • 对象的操作 with 语句包裹的代码块。在执行该代码块之前,会调用上下文管理器的__enter__()方法;在执行代码块之后,会执行__exit__()方法。

5.2 上下文管理器

下面来介绍与上下文管理器有关的概念。
(1)上下文管理协议
  包含__enter_ ()和__exit_() 方法,支持该协议的对象要实现这两个方法 关于这两个方法的介绍如下:

  • __enter __(self) :进入上下文管理器时调用此方法,其返回值被放入 with-as 语句中 as说明符指定的变量中。
  • exit(self type, value, tb): 离开上下文管理器调用此方法 如果有异常- 出现, type、value、tb 分别为异常的类型、值和追踪信息;如果没有异常,三个参数均设为 None 此方法返回值为 True 或者 False ,分别指示被引发的异常得到了还是没有得到处理,如果返回 False ,引发的异常会被传递出上下文。

(2)上下文管理器
  支持上下文管理协议的对象,用于实现__enter__()、 exit()方法 ,上下文管理器定义执行with 语句时要建立的运行时上下文 ,负责执行with 语句块上下文中的进入与退出操作。
(3) 运行时上下文
  由上下文管理器创建,通过上下文管理器的_enter_()、 _exit_()方法实现。
(4)上下文表达式
  with 语句中在关键字 with 之后的表达式 该表达式要返回一个支持了上下文管理协议的对象。在了解上下文管理器之后,就能很好地理解with语句的整个执行过程了,具体如下:

  • 首先执行上下文表达式,生成一个上下文管理器对象;
  • 接着,调用上下文管理器__enter__() 方法,如果使用了 as 子句,就把__enter__()方法的返回值赋值给 as 子句中的资源对象;
  • 然后,执行 with 语句包裹的代码块;
  • 无论在执行的过程中是否发生异常,都会执行上下文管理器的__exit__() 该方法负责执行程序的"清理"工作,如释放资源等;
  • 如果执行过程中没有出现异常,或者代码块中执行了 break continue 或者 return 语句,则以 None 作为参数调用__exit__() 方法,如果在执行过程中出现异常,则会使用 sys.exc_info得到的异常信息为参数调用__exit__() 方法;
  • 出现异常时,如果 __exit__()方法返回的结果为 False ,则会重新抛出异常 ,让with之外的语句逻辑来处理异常,这是通用做法;如果返回 True,则忽略异常,不再对异常进行处理。

你可能感兴趣的:(python基础知识)