今日内容回顾7.12

异常捕获

  • 什么是异常

    异常就是程序运行的过程中出现了错误导致整个程序直接结束!!!

    也就是程序中出现的报错也称之为bug!!!

  • 异常的结构

  1. 关键字line所在行,精确的提示你哪一行代码出现的问题

    下方也会列出,出错的代码。

  2. 最后一行冒号的左侧,提示信息是错误的类型

  3. 最后一行冒号右侧,提示错误的具体原因

  • 异常的类型

    异常的类型有很多种,以下简单的列举几种。

    NameError
    IndexError
    KeyError
    SyntaxError
    TypeError
    
  • 异常的分类

    • 语法异常

      语法异常是指在编写代码过程中语法不全、语法格式不规范等导致的。

      是我们在编写代码中不允许出现的,一旦出现立即改正。

    • 逻辑异常

      逻辑异常是指在编写代码过程中,可能会因为思想中的情况与现实中代码不一致

      这种问题可以出现,出现后改正即可,问题不大!!!

异常捕获实参演练

  • 异常处理方式

    • 方式1

      基本语法结构

      try:
          name 
          """可能会出错的代码(被try监控)"""
      except NameError as e:
      """except(关键字) NameError(错误类型) as e:(e就是具体错误的原因)"""
      	name = 'jason' # 对应错误类型的解决措施
      

      可以使用多个也可以使用单个,这种方式针对性很强。需要写入准确的错误类型

      或者如下填写多个所猜测的不确定类型,但是一旦错误类型不匹配同样抛出异常。

      try:
          name 
      except NameError as e:
      	name = 'jason' # 对应错误类型的解决措施
      except 错误类型1 as e:  # e就是具体错误的原因
      	对应错误类型1的解决措施
      except 错误类型2 as e:  # e就是具体错误的原因
      	对应错误类型2的解决措施
      except 错误类型3 as e:  # e就是具体错误的原因
      	对应错误类型3的解决措施
      except 错误类型4 as e:  # e就是具体错误的原因
      	对应错误类型4的解决措施
      
    • 方式2

      万能异常处理

       # 示例1
      try123+'hello'
      """万能异常处理方式1"""
      except Exception as e:
      """对应的解决措施"""
      # 示例2
      try:
      	d = {'name':'jason'}
      	d['pwd']
      """万能异常处理方式21"""
      except BaseException as e:
      """对应的解决措施"""
      
  • 异常捕获的其他操作补充

    1. else与finally

      try:
          name ='jason'
      except Exception as e:
          print(1111)"""try监测的代码出现问题则会执行此代码"""
      else:
          print(222222)
          """try监测的代码没有出现异常则会执行else的子代码"""
      finally:
          print(333333)
          """try监测的代码无论是否出现异常都会执行finally的子代码"""
      
    2. 断言

      断言语句是一种调试工具,用来测试某个断言条件,如果断言条件为True

      则程序继续正常执行,如果是false则会抛出异常。

      name = 'jason'  # 通过一系列的手段获取来的数据
      assert isinstance(name, list)  # 断言数据属于什么类型 如果不对则直接报错 对则正常执行下面的代码
      print('针对name数据使用列表相关的操作')
      
    3. 主动抛出异常

      关键字(raise)

      name = input("username>>>:").strip()
      if name == 'jason':
          """条件成立后主动抛出异常"""
          raise Exception('提示错误信息'"""raise后面的异常类型不写,默认抛出当前错误类型
             如果有写错误类型则抛出当前所写类型,异常类型后面的提示代码
             如果有写则返回该提示信息如果没有则没有
          """
      else
          print('判断不成立后执行的结果')
      """
      异常捕获能尽量少用就尽量少用
      被try监测的代码能少就少,节省内存资源消耗!!!
      
      """
      

异常捕获练习

  1. 使用while+异常捕获实现for循环功能

    list1 = [1,2,3,4,5,6]
    res = list1.__iter__()
    while True:
        try:
            print(res.__next__())
        except Exception:
                break
    
    
  2. 实际项目错误演示

     user_data = {
        '1': {'name': 'jason', 'pwd': '123', 'access': ['1', '2', '3']},
        '2': {'name': 'kevin', 'pwd': '321', 'access': ['1', '2']},
        '3': {'name': 'oscar', 'pwd': '222', 'access': ['1']}}
        is_login = {
            'is_login': False,
            'access_list': [] }
        def login_auth(func_id):
            def outer(func):
                def inner(*args, **kwargs):
                    if is_login.get('is_login'):
                        access = is_login.get('access')
                        if func_id in access:
                            res = func(*args, **kwargs)
                            return res
                        else:
                            print('你当前没有编号为%s的函数执行权' % func_id)
                    else:
                        user_id = input('请输入用户编号>>>').strip()
                        if user_id in user_data:
                            username = input('请输入用户名>>>').strip()
                            pwd = input('请输入密码>>>').strip()
                            real_dict = user_data.get(user_id)
                            if username == real_dict.get('name') and pwd == real_dict.get('pwd'):
                                access = real_dict.get('access')
                                is_login['is_login'] = True
                                is_login['access_list'] = access
                                if func_id in access:
                                    res = func(*args, **kwargs)
                                    return res
                                else:
                                    print('你没有当前功能编号为%s的函数执行权' % func_id)
                return inner
            return outer
        @login_auth('1')
        def func1():
            print('from func1')
        func1()
        
        '''
    1.先看最后一行冒号右边的具体的报错信息
    2.再看line所在的那行具体的定位信息
    3.然后看line所在行下面的报错显示的错误代码
    4.注意力就关注在出现这个变量的代码身上即可
    '''
    

生成器对象

  • 什么是生成器对象

    生成器的本质就是迭代器对象

    只不过迭代器是解释器给我们提供的,而生成器是我们直接定义的。

  • 生成器对象的作用

    生成器对象可以优化代码,是一种不依赖索引取值的通用方式

    可以节省数据类型占用内存空间的问题。

  • 生成器对象代码实现

    函数+关键字yield的使用

    """
    当函数体代码中有yield关键字
    那么函数名第一次加括号调用不会执行函数体代码
    而是由普通的函数变成了生成器对象
    """
    def index():
        print('我是函数体代码1')
        yield '我是返回值1'
        print('我是函数体代码2')
        yield '我是返回值1'
    print(index())
    # <generator object index at 0x0000021DE9F5CAC0>
    res = index()
    print(res)
    # <generator object index at 0x0000025F24A4CAC0>
    # 此时的res就是一个生成器对象也就是迭代器对象
    
    res.__next__()  # 我是函数体代码1
    res.__next__()  # 我是函数体代码2
    """
    yield可以在函数体代码中出现多次
    每次调用__next__方法都会触发执行函数体代码
    直到遇到yield代码停留在此处,等待下一次调用
    """
    print(res.__next__())
    print(res.__next__())
    # 我是函数体代码1
    # 我是返回值1
    # 我是函数体代码2
    # 我是返回值1
    
    """
    yield后面如果有数据值 则会像return一样返回出去
    如果有多个数据值逗号隔开 那么也会自动组织成元组返回
    """
    
    
    
  • 课堂练习

    编写生成器实现内置函数range方法的功能

    def my_range(x, y=0, z=1):
        z = abs(z)
        if y:
            x, y = y, x
        while y < x:
            yield y
            y += z
    for i in my_range(1,10,2):
        print(i)  # 1、3、5、7、9
    
    

yield其他用法

  • yield与send结合用法

    yield不单单向外面返回数据还可以接收数据

    def index(name,food=None):
        print(f'{name}准备干午饭!!!')
        while True:
            food = yield
            print(f'{name}正在{food}')
    res = index('jason')
    res.__next__()
    # 传值给yield并自动调用__next__方法
    res.send('吃生蚝')  # jason正在吃生蚝
    res.send('吃烤羊腰子')  # jason正在吃烤羊腰子
    res.send('做大宝剑')  # jason正在做大宝剑
    # 生成器res调用send方法可以向yield传值,并调用__next__方法
    

生成器表达式

  • 什么是生成器表达式

    可以简单的理解为使用for能够快速的构造一个生成器对象。

    tuple1 = ( i for i in range(10) )
    print(tuple1)  # <generator object <genexpr> at 0x00000249C8ACCAC0>
    # 此时的tuple1就是一个生成器对象,可以多次调用__next__方法将其依次取出。
    print(tuple1.__next__())  # 0
    print(tuple1.__next__())  # 1
    print(tuple1.__next__())  # 2
    # 也可以使用类型转换将其转换为列表类型全部取出。
    print(list(tuple1))  # [3, 4, 5, 6, 7, 8, 9]
    
    # 面试题
    def add(n, i):  # 普通函数 返回两个数的和  求和函数
        return n + i
    def test():  # 生成器
        for i in range(4):
            yield i
    g = test()  # 激活生成器
    for n in [1, 10]:
        g = (add(n, i) for i in g)
        """
        第一次for循环
            g = (add(n, i) for i in g)
        第二次for循环
            g = (add(10, i) for i in (add(10, i) for i in g))
        """
    res = list(g)
    print(res)
    
    #A. res=[10,11,12,13]
    #B. res=[11,12,13,14]
    #C. res=[20,21,22,23]
    #D. res=[21,22,23,24]
    ps:掌握技巧即可 无需深究 纯粹为了考试而出 没有多少实际意义 嵌套不符合编程规范
    
posted @   瓮小辉  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示