python基础16 异常捕获与生成器

395 阅读5分钟

异常捕获

异常捕获的了解介绍

  • 对于异常的理解?
    • 通俗的来讲,异常也就是bug(让整个程序非正常结束)
  • 异常的结构是什么样的?
    • 如图: image.png
      1. line 所指就是出错的一行代码
      1. 最后一行冒号左侧是出错的类型
      1. 冒号右侧是错误的原因(关键)
  • 异常的分类
    • 语法错误:不可以出现,很不专业
    • 逻辑错误:允许出现,出现修改就行
  • 异常的类型
    异常名称	                 描述
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	               一般的解释器系统错误
ValueError	               传入无效的参数
UnicodeError	               Unicode 相关的错误
UnicodeDecodeError	       Unicode 解码时的错误
UnicodeEncodeError	       Unicode 编码时错误
Warning	                       警告的基类
DeprecationWarning	       关于被弃用的特征的警告
FutureWarning	               关于构造将来语义会有改变的警告
OverflowWarning	               旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning      关于特性将会被废弃的警告
RuntimeWarning	               可疑的运行时行为(runtime behavior)的警告
SyntaxWarning	               可疑的语法的警告
UserWarning	               用户代码生成的警告
FileNotFoundError	       文件未找到错误

异常捕获实参

  • 为什么要自己写代码处理异常?
    • 为了提前预测可能会出现的报错情况
    • 不确定自己的代码什么时候报错时,需要用到(比如访问网址突然断网就会用到)
  • 怎么用代码实现异常捕获呢?
    • 基本语法结构:
    try:
        try监控的可能出错的代码
    except 错误类型1 as e:
        错误类型1的解决办法
    except 错误类型2 as e:
        错误类型2的解决办法
    except ...(可以一直写错误类型下去)
    
    # 结构中的e是指具体的错误原因   
    
    • 万能异常结构:
    try:
        try监控的可能出错的代码
    except Exception/BaseException as e:
        print(e)
    
    # Exception与BaseException使用一个就行
    
  • 其他异常捕获操作:
      1. else+finally
      try:
          try监测的可能会出错的代码
      except Exception as e:
          print('报错了')
      else:
          print('try监测的代码没有出错,正常结束运行')
      finally:
          print('不管try监测的代码有无报错,最后都会执行finally内的代码')
      
      1. 断言
          name = 'tom'                    # 通过变量名绑定数据值为例(自定义)
          assert isinstance(name, list)   # 直接下定结论数据属于什么类型,正常往下执行,错误报错
          print('针对name数据使用列表相关操作')
      
      1. 主动抛出异常
      name = input('输入用户名').strip()
      if name == 'jerry':
          raise Exception('不通过')   # 使用NameError也可以,但是Exception更加万能
      else:
          print('通过了')
      

异常捕获练习

  • for循环内部的本质其实就是while循环与异常捕获的结合
    • 使用while+异常捕获该怎样实现for循环呢?
      l1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      res = l1.__iter__()
      while True:
          try:
              print(res.__next__())
          except Exception as e:
              break
      
  • bug排查解决事项
    • 1.由下往上解决报错
    • 2.先看具体报错信息
    • 3.再看具体定位信息
    • 4.将错误缩小到具体变量
    • 5.关注这个变量出现的地方

生成器

生成器对象

生成器对象了解介绍

  • 生成器对象的的含义:
    • 我们自定义出__iter__和__next__本质为迭代器对象的就是生成器对象。
  • 为什么要用到生成器对象?
    • 为了优化代码,生成器对象不仅会取消对索引取值的依赖,更好的是可以数据类型的内存占用空间
  • 怎么实现生成器对象?
    def index():
        print('老板这瓜多少钱一斤啊,2块,')
        yield 1, 2, 3
        print('你这瓜皮是金子做的还是瓜粒子是金子做的')
        yield 2
        print('你故意找茬不是,你要不要吧')
        yield 3
    
    print(index)
    res = index()
    print(res)
    res.__next__()
    res.__next__()
    res.__next__()
    
    • yield关键字的用法
    1. 函数体代码中如果有yield关键字,第一次调用将函数变成了迭代器对象(生成器),不执行函数体代码。
    2. yield可以在函数中出现许多次。
    3. yield后有数据值会像return一样返回。
    4. yield方法每次遇到从上往下调用__next__方法都会停留到yield前。
    
    * 其他用法:
        def index(name,food=None):
            print(f'{name}准备干午饭!!!')
            while True:
                food = yield
                print(f'{name}正在吃{food}')
        res = index('jason')
        res.__next__()
        res.send('生蚝')  # 传值并自动调用__next__方法
        res.send('韭菜')  # 传值并自动调用__next__方法
        res.send('腰子')  # 传值并自动调用__next__方法
    
        ```
    

生成器对象练习

  • 实现range方法的功能(一步步完善)
    • 两个参数怎么编写
      def my_range(start, end):
          while start < end:
              yield start
              start += 1
      for i in my_range(1, 10):
          print(i)
      
    • 一个参数完善
        # 第一个形参默认从零开始的,所以第一个要赋值,但是形参的顺序要符合规范,所以在输出的时候,需要进行重新赋值
      def my_range(start, end=None):  
          if not end:
              end = start
              start = 0
          while start < end:
              yield start
              start += 1
      for i in my_range(3, 10):
          print(i)
      
    • 三个参数都完善
        # 参数格式由简单到复杂所以第三个形参在定义也要先赋值
      def my_range(start, end=None, step=1):
          if step < 1:
              step = 1
          if not end:
              end = start
              start = 0
          while start < end:
              yield start
              start += step
      for i in my_range(68, 100, 3):
          print(i)
      

生成器表达式

l1 = [i**2 for i in range(10) if i > 3]
print(l1)          # 加的中括号输出是一个列表

l1 = (i**2 for i in range(10) if i > 3)
print(l1)          # 加小括号输出的就是表达式,存在内存中,需要时才从内存中拿,省内存。 



def add(n, i): # 普通函数
    return n + 1
def test():    # 生成器
    for i in range(4):
        yield i
g = test()     # 激活生成器
for n in [1, 10]:
    g = (add(n, i) for i in g)   # g是生成器对象,必需要执行__next__否则不走
res = list(g)
print(res)