欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

生成器,生成器表达式,列表推导式,内置函数I

程序员文章站 2022-04-15 15:56:37
1. 内容大纲 1. 生成器 yield yield与 return send方法(了解) yield 与 yield from 2. 生成器表达式,列表推导式 3. 内置函数 I 2. 具体内容: 生成器 生成器:python社区,生成器与迭代器看成是一种。生成器的本质就是迭代器。唯一的区别:生成 ......
  1. 内容大纲

    1. 生成器

      • yield
      • yield与 return
      • send方法(了解)
      • yield 与 yield from
    2. 生成器表达式,列表推导式

    3. 内置函数 i

  2. 具体内容:

    • 生成器

      • 生成器:python社区,生成器与迭代器看成是一种。生成器的本质就是迭代器。唯一的区别:生成器是需要我们自己用python代码构建的数据结构。迭代器都是python给你提供的已经写好的工具或者通过数据转化得来的(比如文件句柄,iter([1,2,3])。
        • 创建(获取)生成器的三种方式:
          • 通过生成器函数。
          • 通过生成器表达式。
          • python内置函数或者模块提供
      • 生成器函数获得生成器:
      函数:
      def func():
          print(111)
          print(222)
          return 3
      ret = func()
      print(ret)
      111
      222
      3
      
      生成器函数也叫生成器,通过生成器函数构建生成器:
      
      def func():
          print(11)
          yield 22
          yield 33
      ret = func()  #获取生成器对象
      print(ret) # <generator object func at 0x000002003a91b1a8>  #generator 生成器
      next(ret) # 11   next让指针停留在第一个yield后面。生成器取值但未打印
      print(next(ret)) # 33   生成器取值
      生成器的本质就是迭代器.迭代器如何取值,生成器就如何取值:next会获取对应yield生成的元素。一个yield对应一个next,next超过yield数量(最后⼀个yield执⾏完毕. 再次next),就会报错
      
      def func():
          print(111)
          print(222)
          yield 3
          a = 1
          b = 2
          c = a + b
          print(c)
          yield 4
      ret = func()
      print(ret)#<generator object func at 0x000001d73472b1a8>
      print(next(ret))#next让指针停留在第一个yield后面。一个next对应一个yield
      # 111
      # 222
      # 3
      print(next(ret))#保留了上次的位置,从第一个yield后面开始执行,最终next让指针停留在第二个yield后面。一个next对应一个yield
      # 3
      # 4
      
      
      • yield 与 return的区别:

        return:一般在函数中只设置一个,它的作用是终止函数,并且给函数的执行者返回值。
        
        yield:只要函数中有yield,那么这个函数就是一个生成器函数(生成器),而不是函数了。在执行这个函数的时候.就不再是函数的执行了.而是获取这个生成器对象。
        yield:在生成器函数中可设置(存在)多个yield.,yield不会结束生成器函数,一个yield对应一个next。
      • 吃包子练习题:

        #非常直观,但占用内存
        def func():
            l1 =[]
            for i in range(1,5001):
                l1.append(f'{i}号包子')
            return l1
        ret = func()
        print(ret)
        
        #非常的节省内存,而且还可以保留上次的位置
        def gen_func():
            for i in range(1,5001):
                yield f'{i}号包子'
        ret = gen_func()
        print(ret)#<generator object gen_func at 0x0000016ad3d1b1a8>
        for i in range(200):  #从1号包子到200号包子
            print(next(ret))
        
        for i in range(300):  #从201号包子到500号包子,多次next包子的号码是按照顺序记录的。
            print(next(ret))
        
      • send方法(了解)

        # next只能获取yield生成的值,但是不能传递值
         def gen(name):
             print(f'{name} ready to eat')
             while 1:
                 food = yield
                 print(f'{name} start to eat {food}')
         dog = gen('alex')
         next(dog)  #alex ready to eat    第一次next让指针停留在第一个yield后面
         next(dog)  #alex start to eat none  能记住上次的位置,再次执行从yield后面开始执行,最后又停在yield后面
         next(dog)  #alex start to eat none  同上
        
        
        #send不仅能获取yield生成的值,还能传递值
         def gen(name):
             print(f'{name} ready to eat')
             while 1:
                 food = yield 222
                 print(f'{name} start to eat {food}')
         dog = gen('alex')##获取生成器对象
         next(dog)  # alex ready to eat  第一次必须用next让指针停留在第一个yield后面
         ret = dog.send('骨头')#alex start to eat 骨头
         print(ret)#222   # 与next一样,可以获取到yield的值
        
        
         def gen(name):
             print(f'{name} ready to eat')
             while 1:
                 food = yield
                 print(f'{name} start to eat {food}')
         dog = gen('alex')
         next(dog)#alex ready to eat
         # 可以给上一个yield发送值
         dog.send('骨头')#alex start to eat 骨头
         dog.send('狗粮')#alex start to eat 狗粮
         dog.send('香肠')#alex start to eat 香肠
        
        
        send 和 next()区别:
            相同点:
                send 和 next()都可以让生成器对应的yield向下执行一次。
                都可以获取到yield生成的值。
            不同点:
                第一次获取yield值只能用next不能用send(可以用send(none))。
                send可以给上一个yield置传递值。'''
        
      • yield 与 yield from

        yield from:可以直接把可迭代对象中的每一个数据作为生成器的结果进行返回
        
        def func():
            l1 = [1,2,3,4,5]
            yield l1
        ret = func()
        print(ret)#<generator object func at 0x00000162756fb1a8>
        print(next(ret))#[1, 2, 3, 4, 5]
        
        def func():
            lst = ['卫龙','老冰棍','北冰洋','牛羊配']
            yield lst
        ret = func()
        print(ret)#<generator object func at 0x000001b7a853b0f8>
        print(next(ret))  # 只是返回一个列表['卫龙', '老冰棍', '北冰洋', '牛羊配']
        
        
        【面试题】
        def func():
            lst = ['卫龙','老冰棍','北冰洋','牛羊配']
            yield from lst  #将lst这个列表变成了迭代器返回,它会将这个可迭代对象(列表)的每个元素当成迭代器的每个结果进行返回。
        '''  yield from lst 相当于下面的:
            yield '卫龙'
            yield '老冰棍'
            yield '北冰洋'
            yield '牛羊配'
        '''
        ret = func()
        print(ret)# <generator object func at 0x0000026314efb0f8>
        print(next(ret))  #卫龙
        print(next(ret))  #老冰棍
        print(next(ret))  #北冰洋
        print(next(ret))  #牛羊配
        
        
        def func():
            l1 = [1, 2, 3, 4, 5]
            yield from l1
        ret = func()
        for i in range(5):
            print(next(ret))
        
        
        
        #有个小坑,
        yield from 是将列表中的每一个元素返回, 所以如果写两个yield from 并不会产生交替的效果
        
        def func():
            lst1 = ['卫龙', '老冰棍', '北冰洋', '牛羊配']
            lst2 = ['馒头', '花卷', '豆包', '大饼']
            yield from lst1
            yield from lst2
        g = func()
        for i in g:
            print(i)
        # 卫龙
        # 老冰棍
        # 北冰洋
        # 牛羊配
        # 馒头
        # 花卷
        # 豆包
        # 大饼
        
        
    • 生成器表达式,列表推导式

      • 用一行代码构建一个比较复杂有规律的列表。

         l1 = []
         for i in range(1,11):
             l1.append(i)
         print(l1)#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        
        #列表推导式:
         l1 = [i for i in range(1,11)]
         print(l1)#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      • 字典推导式(了解)
        lst1 = ['jay', 'jj', 'meet']
        lst2 = ['周杰伦','林俊杰','元宝']
        dic = { lst2[i]: lst1[i] for i in range(len(lst1))}
        print(dic)#{'周杰伦': 'jay', '林俊杰': 'jj', '元宝': 'meet'}
        
        
        集合推导式(了解)
        print({i for i in range(1,11)})
      • 列表推导式:

        • 缺点:
             1,有毒。列表推导式只能构建比较复杂并且有规律的列表。 不要太着迷。
             2,超过三层循环才能构建成功的,就不建议用列表推导式。
             3,查找错误(debug模式)不行
          优点:
               一行构建,简单。
          
        • 循环模式:[变量(加工后的变量) for 变量 in iterable]

          # 将10以内所有整数的平方写入列表。
           ret = [i**2 for i in range(1,11)]
           print(ret)
          
          # 100以内所有的偶数写入列表.
           print([i for i in range(2, 101, 2)])
          
          # 从python1期到python100期写入列表lst
           print([f'python{i}期' for i in range(1,101)])
          
          #【*】一行代码构建[2, 3, 4, 5, 6, 7, 8, 9, 10, 'j', 'q', 'k', 'a']
           l1 = [i for i in range(2,11)] + list('jqka')
           print(l1)#[2, 3, 4, 5, 6, 7, 8, 9, 10, 'j', 'q', 'k', 'a']
          
        • 筛选模式:[变量(加工后的变量) for 变量 in iterable if 条件]

          # 30以内能被3整除的数
           l1 = [i for i in range(1,31) if i%3 == 0]
           print(l1)
          
          # 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
           l1 = ['barry', 'ab', 'alex', 'wusir', 'xo']
           print([i.upper() for i in l1 if len(i) >= 3 ])
          
          # 含有两个'e'的所有的人名全部大写留下来
           names = [['tom', 'billy', 'jefferson', 'andrew', 'wesley', 'steven', 'joe'],['alice', 'jill', 'ana', 'wendy', 'jennifer', 'sherry', 'eva']]
            1.正常做法:
             l1 = []
             for i in names:
                 for j in i:
                    if j.count('e') == 2:
                         l1.append(j)
             print(l1)#['jefferson', 'wesley', 'steven', 'jennifer']
            2.列表推导式
             print([j for i in names for j in i if j.count('e') == 2 ])# ['jefferson', 'wesley', 'steven', 'jennifer']
          
          
      • 生成器表达式:
                    列表推导式与生成器表达式区别。
                     1.写法上: [] ()
                     2.iterable:可迭代对象   iterator:迭代器
        
        生成器表达式和列表推导式的区别:
        
        1.列表推导式比较耗内存,所有数据一次性加载到内存。而生成器表达式遵循迭代器协议,逐个产生元素。
        2.得到的值不一样,列表推导式得到的是一个列表。生成器表达式获取的是一个生成器。
        3.列表推导式一目了然,生成器表达式只是一个内存地址。
        
        • 与列表推导式的写法几乎一模一样,也有筛选模式,循环模式,多层循环构建。写法上只有一个不同:[] 换成 ().
          
           print([i for i in range(1,11)]) #列表推导式
           print((i for i in range(1,11))) #生成器表达式
          
           obj = (i for i in range(1,11))
           print(next(obj))
           print(next(obj))
           print(next(obj))
           print(next(obj))
           print(next(obj))
           #或者:
           for i in obj:
               print(i)
          
          
    • 内置函数 i

      #eval:执行字符串类型的代码,并返回最终结果。
          eval('2 + 2')  # 4
          n = 81
          eval("n + 4")  # 85
          eval('print(666)')  # 666
      
          eval 剥去字符串的外衣运算里面的代码,有返回值。网络传输的str input 输入的时候,sql注入等等绝对不能使用eval。
          s1 = '1 + 3'
          print(s1)# 1 + 3
          print(eval(s1))  #4  **
          s = '{"name": "alex"}'
          print(s,type(s))#{"name": "alex"} <class 'str'>
          print(dict(s)) # 不行
          print(eval(s),type(eval(s)))#{'name': 'alex'} <class 'dict'>
      
      
      #exec: 执行字符串类型的代码。 exec 与eval几乎一样, 处理代码流
          s = '''
          for i in [1,2,3]:
              print(i)
          '''
          exec(s)
      
          msg = """
          for i in range(10):
              print(i)
          """
          print(msg)  #for i in range(10):
                        #print(i)
          exec(msg)  0-9
          eval(msg)#报错
      
      
      #hash:获取一个对象(可哈希对象:int,str,bool,tuple)的哈希值。hash只能操作不可变数据类型。
          print(hash(12322))
          print(hash('123'))
          print(hash('arg'))
          print(hash('alex'))
          print(hash(true))
          print(hash(false))
          print(hash((1, 2, 3)))
          print(hash('fsjkdafsda'))
      
      
      
      #help:函数用于查看函数或模块用途的详细说明。
      
          print(help(list))
          print(help(str.split))
      
          s1 = 'fjdsls'
          print(help(str))
          print(help(str.upper))
      
          s1 = 'sfsda'
          s1.upper()
      
      #callable:函数用于检查一个对象是否是可调用的。如果返回true,object仍然可能调用失败;但如果返回false,调用对象ojbect绝对不会成功。
          name = 'alex'
          def func():
              pass
          print(callable(name))  # false
          print(callable(func))  # true
      
      #int:函数用于将一个字符串或数字转换为整型。
          print(int())  # 0
          print(int('12'))  # 12
          print(int(3.6))  # 3
          print(int('0100', base=2))  # 将2进制的 0100 转化成十进制。结果为 4
      
      #float:函数用于将整数和字符串转换成浮点数。
         print(float(3))  # 3.0
      
      #complex:函数用于创建一个值为real + imag * j的复数或者转化一个字符串或数为复数。如果第一个参数为字符串,则不需要指定第二个参数。。
         print(complex(1, 2))  # (1+2j)
      
      #bin:将十进制转换成二进制并返回。
      
      #oct:将十进制转化成八进制字符串并返回。
      
      #hex:将十进制转化成十六进制字符串并返回。
          print(bin(10), type(bin(10)))  # 0b1010 <class 'str'>
          print(oct(10), type(oct(10)))  # 0o12 <class 'str'>
          print(hex(10), type(hex(10)))  # 0xa <class 'str'>
      
      #divmod:计算除数与被除数的结果,返回一个包含商和余数的元组(a // b, a % b)。
      
      #round:保留浮点数的小数位数,默认保留整数。
      
      #pow:求x ** y次幂。(三个参数为x ** y的结果对z取余)
          print(divmod(7, 2))  # (3, 1)
          print(round(7 / 3, 2))  # 2.33
          print(round(7 / 3))  # 2
          print(round(3.32567, 3))  # 3.326
          print(pow(2, 3))  # 两个参数为2**3次幂
          print(pow(2, 3, 3))  # 三个参数为2**3次幂,对3取余。
      
      #bytes:用于不同编码之间的转化。
      
          s = '你好'
          bs = s.encode('utf-8')
          print(bs)
          s1 = bs.decode('utf-8')
          print(s1)
          bs = bytes(s,encoding='utf-8')
          print(bs)
          b = '你好'.encode('gbk')
          b1 = b.decode('gbk')
          print(b1.encode('utf-8'))
      
      
      # ord 输入字符找该字符编码的位置
          print(ord('a'))
          print(ord('中'))
      
      # chr 输入位置数字找出其对应的字符
          print(chr(97))
          print(chr(20013))
      
      #repr: 返回一个对象的string形式(原形毕露)。
      
      # %r  原封不动的写出来
          name = 'taibai'
          print('我叫%r'%name)
      
      # repr 原形毕露
          print(repr('{"name":"alex"}'))
          print('{"name":"alex"}')
      
      # all  可迭代对象中,全都是true才是true
      # any  可迭代对象中,有一个true 就是true
          print(all([1,2,true,0]))
          print(any([1,'',0]))
      
      
  3. 总结

    1. 生成器:***
    2. 生成器函数 yield
    3. yield与return 区别。yield from
    4. 列表推导式,生成器表达式。 ***
    5. 内置函数:内置函数