学习python-Day19


今天学习内容

一、异常捕获

  1. 异常简介

    程序在运行过程中如果出现了异常就会导致整个程序的结束

    异常就是程序员口中的bug

  2. 异常结构
    D:\python38\python.exe D:/pythonProject/kaoshi/one.py
    Traceback (most recent call last):
      File "D:/pythonProject/kaoshi/one.py", line 1, in 
        username
    NameError: name 'username' is not defined
    
    
    描述
    关键字line所在行 精准提示你在哪一行代码出错
    最后一行冒号左侧 表示错误类型
    最后一行冒号右侧 错误的具体原因(也是修bug的关键)
  3. 异常类型
    异常名称 描述
    BaseException 所有异常的基类(父类)
    SystemExit 解释器请求退出
    KeyboardInterrupt 用户中断执行(通常是输入)
    Exception 常规错误的基类()
    StopIteration 迭代器没有更多的值
    GeneratorExit 生成器(generator)发生异常来通知退出
    StandardError 所有的内建标准异常的基类
    ArithmeticError 所有数值计算错误的基类
    FloatingPointError 浮点计算错误

  4. 异常分类
    1. 语法错误:语法结构不对,python会报错误。不允许出现,一旦出现就立刻修改。
    2. 逻辑错误:运行前看不出来错误,运行后就会出现。允许出现,出错之后修改即可。
  5. 异常捕获练习
    1. 什么时候才可能会需要自己写代码处理异常

    2. 异常捕获:提前预测可能出现的问题并提前给出处理的措施

    3. 异常捕获代码实现

      1.基本语法结构(针对性很强)
      	try:
              可能会出现的代码(被try监控)
          except 错误类型1 as e:  # e就是具体错误的原因
          	对应错误类型1的解决措施
          except 错误类型21 as e:  # e就是具体错误的原因
          	对应错误类型2的解决措施
          except 错误类型3 as e:  # e就是具体错误的原因
          	对应错误类型3的解决措施
          except 错误类型4 as e:  # e就是具体错误的原因
          	对应错误类型41的解决措施
       
      2.万能异常(笼统的处理方式)
      	try:
              #name
              # d = {'name': 'jason'}
              # d['pwd']
              123 + 'hello'
          except Exception as e:  # 万能异常方式1
              print(e)
          except BaseException as e:   #万能异常方式2
              print(e)
      
              
      3.异常捕获其他操作补充
      
          3.1 else  |  finally
              try:
                  name
              except Exception as e:
                  print('你出错了!')
              else:
                  print('try监测的代码没有出错的情况下正常运行结束,则会执行else子代码')
              finally:
                  print('try监测的代码无论有没有出错,最后都会执行finally子代码')
      
      
      
          3.2断言
              name = 'xz'   # 通过一系列手段获取来的数据
              assert isinstance(name,list) # 断言数据属于什么类型,如果不对则直接报错,对则正常执行下面的代码
              print('针对name数据使用列表相关的操作')
      
          
          3.3主动抛出异常
              name = input('username>>>:').strip()
              if name == 'xz':
                  # raise NameError('xz长得好帅!!!!')
                  raise Exception('反正就是长得帅!!!')
              else:
                  print('不是xz,那就走吧')
             
         
      注意:
      	1.异常捕获能尽量少用就尽量少用
          2.被try监测的代码能尽量少就尽量少
          因为如果try包含的代码太多,监测太多的话会影响运行也会占资源。
          
         
      4.异常捕获练习
      for循环内部的本质
      	#需求:使用while + 异常捕获实现for循环的功能
          l1 = [11, 22, 33, 44, 55, 66, 77, 88]
          res = l1.__iter__() #将列表变成可迭代对象,赋值给res
          while True:
              try: 
                  print(res.__next__())# res循环调用__next__变成可迭代器对象。监测可能出现异常的部分
              except Exception  as e:
                  break#监测出就里面结束
          
      如果一个项目出现错误我们可以分几步来解决问题:
      	1.先看具体的报错信息,报红的地方。
          2.再看具体的定位信息,有下往上看。
          3.尽量将错误缩小到某个具体的变量
          4.注意力就关注在出现这个变量的代码身上即可
      

二、生成器对象(自定义迭代器对象)

  1. 本质

    就是迭代器对象

    只不过迭代器是解释器提供给我们的(现成的)。

    生成器是我们自定义出来的(自己动手编写)。

  2. 目的

    就我为了优化代码

    一种不依赖索引取值的通用方式。

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

  3. 代码
    def index():
        print('你好!')
        yield  xz, wyb
        print('很高兴认识你们!')
        yield aaaa
        print('未来可期!')
        yield hhhh
      
    
    print(index) #还是属于函数,函数名第一次加括号调用不会执行函数体代码
    res = index() #由普通函数变成了迭代器对象(生成器) 将返回值赋值给变量名
    print(res)    #生成器
    res.__next__()
    res.__next__()
    res.__next__()
    
    '运行结果:
        
        
        你好!
        很高兴认识你们!
        未来可期!
        '
    '''
    当代码有yield关键字
    那么函数名第一次加括号调用不会执行函数体代码
    而是由普通的函数变成了迭代器对象(生成器)将返回值赋值给变量名。
    '''
    
    '''
    yield可以在函数代码中出现多次
    每次调用__next__方法都会从上往下执行直到遇到yield代码停留在此处
    '''
    将上述的res.__next__()都去掉。
    
    print(res.__next__())
    print(res.__next__())
    print(res.__next__())
    '运行结果:
        
        
        你好!
        (11, 22)
        很高兴认识你们!
        333
        未来可期!
        444
        '
     print(res.__next__())  #如果再加一个,会报错。超过了它的取值范围,没有yield了。
    '''
    yield后面如果有数据值,则会像return一样返回出去
    如果有多个数据值逗号隔开,那么也会自动组织成元组返回。
    '''
    
  4. 课堂练习
    编写生成器,实现range方法的功能
    1.可以先先两个参数的功能编号    range(1,10)
    def my_range(start_num, end_num):
        while start_num 
  5. yield
    def index(name, food=None):
        print(f'{name}准备放假!!!')
        while True:
            food = yield #send就是传值给yield赋值左边的变量名。
            print(f'{name}准备放假!!!回{food}')
    res = index('xz')
    res.__next__() #调用__next__()方法
    
    res.send('北京') #传值并调用__next__方法
    res.send('上海') #传值并调用__next__方法
    res.send('深圳') #传值并调用__next__方法
    
    '运行结果:
        xz准备放假!!!
        xz准备放假!!!回北京
        xz准备放假!!!回上海
        xz准备放假!!!回深圳
        '
    

三、生成器表达式

#列表生成式  中括号
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) 
'运行结果:
    [16, 25, 36, 49, 64, 81]
     at 0x000001C937BF4970>
    '

===面试试题====
#普通就和函数
def add(n,i):
    return n + i
#生成器对象 返回 0 1 2 3 
def test():
    for i in range(4)
    yield i 
#将test函数变成生成器
g = test()
#简单的for循环
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))  #n为10
   所以两个n相加最少为20
   里面代码只有对迭代取值的时候才有用
    '''
#list底层就是for循环,相当于对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]

选C