生成器和生成器表达式

 一.生成器

  生成器实质就是迭代器. 

    在python中有三种方式来获取生成器: 

  1. 通过⽣生成器函数

  2. 通过各种推导式来实现生成器

  3. 通过数据的转换也可以获取生成器

1 def    func():
2     print("111")
3     return  222
4 ret = func()
5 print(ret)
6 结果:
      111
      222

将函数中的return换成yield就是生成器

1 def    func():
2     print("111")
3     yield  222
4 ret   = funt()
5 print(ret)
6 
7 结果:
8     <generator object func at 0x10567ff68>

我们可以直接执行__next__()来执行以下生成器.

 1 def   func():
 2     print("111")
 3     yield  222
 4 gener = func()     #这个时候函数不会执行,而是获取到生成器
 5 ret = gener.__next__()  # 这个时候函数才会执行. yield的作用和return一样. 也是返回数据 
 6 print(ret) 
 7 
 8 结果:
      111
      222
 1 def func():
 2     print("111")
 3     yield 222
 4     print("333")
 5     yield 444 
 6 gener = func() 
 7 ret = gener.__next__() 
 8 print(ret) 
 9 ret2 = gener.__next__() 
10 print(ret2)
11 ret3 = gener.__next__()  # 最后一个yield执行完毕. 再次__next__()程序报错, 也就是 说. 和return无关了. 
12 print(ret3) 
13 结果: 
   111 
   Traceback (most recent call last): 
   222 
   333
     File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 55, in <module> 
   444
       ret3 = gener.__next__()  # 最后一个yield执行完毕. 再次__next__()程序报错, 也 就是说. 和return无关了. 
   StopIteration
1 def   cloth()
2     lst = []
3     for i in range(0,10000)
4         lst.append("衣服" +str(i)
5      return  lst
6 cl = cloth()
1 def  cloth():
2     for  i in range(0,10000):
3             yield   "衣服"  + str(i)
4 cl  =  cloth()
5 print(cl.__next__())
6 print(cl.__next__())
7 print(cl.__next__())

  区别: 第一种是直接一次性全部拿出来. 会很占用内存. 第二种使用生成器. 一次就一个. 用多少生成多少.  生成器是一个一个的指向下一个.  不会回去, __next__()到哪, 指针就指到哪儿. 下一次继续获取指针指向的值.

接下来我们来看send⽅法, send和__next__()一样都可以让生成器执行到下一个yield

 1 def eat():
 2     print("我吃什什么啊")
 3     a = yield "馒头"
 4     print("a=",a)
 5     b = yield "大饼"
 6     print("b=",b)
 7     c = yield "韭菜盒子"
 8     print("c=",c)
 9     yield "GAME OVER"
10 gen = eat()     # 获取⽣生成器器 
11 ret1 = gen.__next__() 
12 print(ret1) 
13 ret2 = gen.send("胡辣汤") 
14 print(ret2) 
15 ret3 = gen.send("狗粮") 
16 print(ret3) 
17 ret4 = gen.send("猫粮") 
18 print(ret4)

send和__next__()区别: 

   1.send和next()都是让生成器向下走一次

   2. send可以给上⼀一个yield的位置传递值, 不能给后一个yield发送值. 在第一次执行生成器代码的时候不能使用send()

生成器可以使用for循环来循环获取内部的元素: 

 1 def func():
 2     print(111)
 3     yield 222
 4     print(333)
 5     yield 444
 6     print(555)
 7     yield 666 
 8 gen = func()
 9  for i in gen:
10     print(i) 
11     结果: 
         111
         222  
         333
         444
         555
         666

 二. 列表推导式, 生成器表达式以及其他推导式

列表推导式

   用一句话来生成一个列表 

   语法:

       [ 结果  for  变量  in  可迭代对象] 

1 lst = ['python%s' % i for i in range(1,15)] 
2 print(lst)

筛选模式:

     [ 结果 for 变量 in 可迭代对象 if 条件 ]

1 # 获取1-100内所有的偶数
2  lst = [i for i in range(1, 100) if i % 2 == 0]
3  print(lst)

字典推导式:

1 # 把字典中的key和value互换 
2 dic = {'a': 1, 'b': '2'} 
3 new_dic = {dic[key]: key for key in dic} 
4 print(new_dic) 
5 # 在以下list中. 从lst1中获取的数据和lst2中相对应的位置的数据组成一个新字典 
6 lst1 = ['jay', 'jj', 'sylar'] 
7 lst2 = ['周杰伦', '林俊杰', '邱彦涛'] 
8 dic = {lst1[i]: lst2[i] for i in range(len(lst1))} 
9 print(dic)

集合推导式:

  集合推导式可以帮我们直接生成一个集合. 集合的特点: 无序, 不重复. 所以集合推导式自带去重功能.

1 lst = [1, -1, 8, -8, 12] 
2 # 绝对值去重 
3 s = {abs(i) for i in lst} 
4 print(s)

  总结: 推导式有, 列表推导式, 字典推导式, 集合推导式, 没有元组推导式   

    生成器表达式: (结果 for 变量量 in 可迭代对象 if 条件筛选)     

    生成器表达式可以直接获取到生成器对象. 生成器对象可以直接进行for循环. 生成器具有惰性机制. 

1 def add(a, b):
2     return a + b
3 def test():
4     for r_i in range(4):
5         yield r_i
6 g = test()  
7 for n in [2, 10]:
8     g = (add(n, i) for i in g)
9 print(list(g))
结果:
  [20, 21, 22, 23]

  惰性机制, 不到最后不会拿值

生成器函数:

 生成器表达式和列表推导式的语法基本上是一样的. 只是把[]替换成()

1 gen = (i for i in range(10)) 
2 print(gen) 
3 结果: 
4 <generator object <genexpr> at 0x106768f10> 

生成器表达式也可以进行筛选: 

 1 # 获取1-100内能被3整除的数 
 2 gen = (i for i in range(1,100) if i % 3 == 0) 
 3 for num in gen:
 4     print(num) 
 5 # 100以内能被3整除的数的平方 
 6 gen = (i * i for i in range(100) if i % 3 == 0) 
 7 for num in gen:
 8     print(num) 
 9 # 寻找名字中带有两个e的人的名字 
10 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
11           ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] 
12 # 不不⽤用推导式和表达式 
13 result = [] 
14 for first in names:
15     for name in first:
16         if name.count("e") >= 2:
17             result.append(name) 
18 print(result) 
19 # 推导式 
20 gen = (name for first in names for name in first if name.count("e") >= 2) 
21 for name in gen:
22     print(name)

生成器表达式和列表推导式的区别:

  1. 列表推导式比较耗内存. 一次性加载. 生成器表达式几乎不占用内存. 使用的时候才分配和使用内存

2. 得到的值不一样. 列表推导式得到的是一个列表. 生成器表达式获取的是一个生成器. 

1 def func():
2     print(111)
3     yield 222 
4 g = func()  # 生成器g 
5 g1 = (i for i in g) # 生成器g1. 但是g1的数据来源于g 
6 g2 = (i for i in g1)    # 生成器g2. 来源g1 
7 print(list(g))  # 获取g中的数据. 这时func()才会被执行. 打印111.获取到222. g完毕. 
8 print(list(g1))  # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了了. g1 也就没有数据了 
9 print(list(g2))  # 和g1同理
原文地址:https://www.cnblogs.com/chenxi67/p/9469011.html