# 异常处理

# 什么是异常处理

  • 程序中的两种异常

    • 1、语法错误: 空格 缩进以及其他语法规则(一般在语法检测的时候就会报错)
    • 2、逻辑错误:程序整体能编译,但是在运行时,因具体的逻辑出现问题,例如:input的内容转int
    • 3、异常就是程序运行时发生错误的信号,在Python中,错误触发的异常如下:异常发生后后面的代码不执行。
  • 在python中不同异常可以用不同的类型去标识(python将同一类型的错误类型进行统一),不同的类对象标识不同的异常。

                                               常见异常
                                               
    AttributeError 			试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
    IOError 				输入/输出异常;基本上是无法打开文件
    ImportError 			无法引入模块或包;基本上是路径问题或名称错误
    IndentationError 		语法错误(的子类) ;代码没有正确对齐
    IndexError 				下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
    KeyError 				试图访问字典里不存在的键
    KeyboardInterrupt        Ctrl+C被按下
    NameError 				使用一个还未被赋予对象的变量
    SyntaxError Python		代码非法,代码不能编译(个人认为这是语法错误,写错了)
    TypeError 			    传入对象类型与要求的不符合
    UnboundLocalError     试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
    					  导致你以为正在访问它
    ValueError 				传入一个调用者不期望的值,即使值的类型是正确的
    
    
  • Python中常见的异常类

    • BaseException # 所以异常的基类
    • SystemExit # 解释器请求退出
    • KeyboardInterrupt # 用户中断执行(^C)
    • Exception # 常规错误的基类
  • Stoplteration # 迭代器没有更多值……

  • 异常处理:通过捕捉异常,使程序进入另一个处理分支,执行特定的逻辑,使程序不崩溃

  • 异常处理的目的:提高用户体验,提高代码的容错性

  • 为什么要进行异常处理:检测到了一个错误时,触发异常,异常触发后且没被处理的情况下,程序就在当前异常处终止,后面的代码不会运行,谁会去用一个运行着突然就崩溃的软件。

# 如何进行异常处理

  • 1、if判断式: 最常见的if语句只是针对一行代码,如果有多行需要使用多个if判断式

  • 2、python为每一种异常定制了一个类型,提供特定的语法结构

    • 1、try …… except……

      try:
           被检测的代码块
      except 异常类型:
           try中一旦检测到异常,就执行这个位置的逻辑
      #实例一:   
      try:
          f = open('a.txt')
          g = (line.strip() for line in f)
          print(next(g))
          print(next(g))
          print(next(g))
          print(next(g))
          print(next(g))
      except StopIteration:
          f.close()    
       
      --------------------------------------------------------
      #实例二:
      s1 = 'hello'
      try:
          int(s1)
      # except IndexError as e:   # 如果捕捉不到相应的异常则报错
      except ValueError as e:
          print (e)  #invalid literal for int() with base 10: 'hello'
      
      
    • 多分支

      # try……except……except……
      s1 = 'hello'
      try:
          int(s1)
      except IndexError as e:
          print(e)
      except KeyError as e:
          print(e)
      except ValueError as e:
          print(e)
         
      #万能异常 Exception,他可以捕获任意异常
      s1 = 'hello'
      try:
          int(s1)
      except Exception as e:  #e是异常的报错信息
          print(e)
          
      #如果你统一用Exception,没错,是可以捕捉所有异常,但意味着你在处理所有异常时都使用同一个逻辑去处理(这里说的逻辑即当前expect下面跟的代码块,如果你想要的效果是,对于不同的异常我们需要定制不同的处理逻辑,那就需要用到多分支了
      
      #try……except……else……
      try:
          choose = int(input('请输入您想选择的商品序号 :'))
          print(l[choose-1])
      except (ValueError,IndexError) as e1:  #这里括号里可以写一类操作后出现的报错,以便做同样的处理逻辑
          print(e1)
          print('请输入一个正常的序号')
      except Exception as e2:  #如果上面异常被捕获就跳过
          print(e2)
      else:
          print('执行我啦')
          
      # else: 如果try中的代码顺利的执行完,没有报错,那么就执行else中的代码是用来汇报整个try中的代码执行成功用的
      # 一般情况下 else中的内容都是安全的不会有报错隐患,用于打印,区分在报错代码下一行执行
      
      #try……except……except……finally……      try……finally……
      def func(filename):
          try:
              f = open(filename,'r')
              content = f.read()
              return content
          except Exception as e:
              print(e)
          finally:        # 无论如何都要执行  用于一些必要的收尾工作
              f.close()
              print('一定会执行')
      
      ret = func('test') 
      print(ret)   #一定会执行   wjhal
      # finally : 必须执行
          # 遇到return也先执行finally中的代码  ***
          # 遇到报错也在程序结束之前先执行finally中的代码 ***
          
      #列题
      def wrapper(func):
          def inner(*args,**kwargs):
              try:
                  print('before func')
                  return func(*args,**kwargs)  # 在return之前还是会执行finally
              finally:
                  print('after func')
          return inner
      
      @wrapper
      def func():
          print('在 func中') 
      func()   #结果 before func  在 func中   after func
      
  • 主动抛异常

    • raise 异常名称('打印信息') 一般结合自定义异常类使用,下文讲

      raise ValueError('类型错误')  # ValueError: 类型错误
      
      class Empty(Exception):
          def __init__(self,msg):
              self.msg = msg
              super().__init__()
          def __str__(self):
              return self.msg
         
      raise Empty('我报错了!')  #__main__.Empty: 我报错了!
      
      -----------------------------------------------------------
      #2、自定义异常类
      class Empty(Exception):  #自定义类
          def __init__(self,msg):
              self.msg = msg
              super().__init__()
          def __str__(self):
              return self.msg
          
      class 班级:
          def __init__(self):
              self.students = ['赵大宝']
      
          def get(self):
              if not self.students:
                  raise Empty('学生列表已为空')
              else:
                  return self.students.pop()
      
      clas = 班级()
      stu1 = clas.get()
      print(stu1)   #赵大宝
      stu2 = clas.get()
      print(stu2)  #__main__.Empty: 学生列表已为空
      
  • 断言:Python的断言就是检测一个条件,如果条件为真,它什么都不做;反之它触发一个带可选错误信息的AssertionError。

    #1、
    assert 1 == 5,'1 不等于 5 在报错时打印这段话'    #AssertionError: 1 不等于 5 在报错时打印这段话
    
    #2、unittest常用的断言方法:
        1.assertEqual(self, first, second, msg=None)
        	--判断两个参数相等:first == second
        2.assertNotEqual(self, first, second, msg=None)
        	--判断两个参数不相等:first != second
        3.assertIn(self, member, container, msg=None)
        	--判断是字符串是否包含:member in container
        4.assertNotIn(self, member, container, msg=None)
        	--判断是字符串是否不包含:member not in container
        5.assertTrue(self, expr, msg=None)
        	--判断是否为真:expr is True
        6.assertFalse(self, expr, msg=None)
        	--判断是否为假:expr is False
        7.assertIsNone(self, obj, msg=None)
        	--判断是否为None:obj is None
        8.assertIsNotNone(self, obj, msg=None)
    
  • 自定义异常

    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)  #类型错误