⽣成器和⽣成器表达式

一丶生成器和生成器函数

什么是⽣成器. ⽣成器实质就是迭代器.
在python中有三种⽅式来获取⽣成器:

1. 通过⽣成器函数
2. 通过各种推导式来实现⽣成器
3. 通过数据的转换也可以获取⽣成器

def func():
 print("111")
 return 222
ret = func()
print(ret)
结果: 
111
222

将return 转换成 yield

def func():
 print("111")
 yield 222
ret = func()
print(ret)
结果: 
<generator object func at 0x10567ff68>
生成器的本质就是迭代器
def func():
    print("娃哈哈")
    yield 1 # return和yield都可以返回数据
    print("呵呵呵")


gen = func() # 不会执行你的函数. 拿到的是生成器


# 函数中如果有yield 这个函数就是生成器函数. 生成器函数() 获取的是生成器. 这个时候不执行函数
# yield: 相当于return 可以返回数据. 但是yield不会彻底中断函数. 分段执行函数.
gen.__next__() #执行函数. 执行到下一个yield.
gen.__next__()  #继续执行函数到下一个yield.
生成器的特点和迭代器一样.取值方式和迭代器一样(__next__(), send(): 给上一个yield传值).
 1 def order():
 2     lst = []
 3     for i in range(10000):
 4         lst.append("衣服"+str(i))
 5     return lst
 6 
 7 ll = order()
 8 
 9 def order():
10     for i in range(10000):
11         yield "衣服"+str(i)
12 g = order() # 获取生成器
13 mingwei = g.__next__()
14 print(mingwei)
15 zhaoyining = g.__next__()
16 print(zhaoyining)
View Code
 1 def func():
 2     print("我是第一个段")
 3     a = yield 123
 4     print(a)
 5     print("石可心是第二段")
 6     b = yield 456
 7     print(b) # ??
 8     print("赵一宁是第三段")
 9     c = yield 789
10     print(c)
11     print("刘伟是最后一个段")
12     yield 79  # 最后收尾一定是yield
13 
14 
15 
16 g = func()
17 print(g.__next__()) # 没有上一个yield 所以不能使用send() 开头必须是__next__()
18 print(g.send("煎饼果子"))
19 print(g.send("韭菜盒子"))
20 print(g.send("锅包肉"))  ## ??
View Code
生成器一般由生成器函数或者生成器表达式来创建
 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 
12 ret1 = gen. __next__()
13 print(ret1) # 馒头
14 ret2 = gen.send("胡辣汤")
15 print(ret2)
16 
17 ret3 = gen.send("狗粮")
18 print(ret3)
19 ret4 = gen.send( "猫粮")
20 print(ret4)
View Code

二丶推导式

1. 列表推导式 [结果 for循环 条件筛选]
lst = []
for i in range(1, 16):
    lst.append("python"+str(i))
print(lst)

推导式: 用一句话来生成一个列表
lst = ["python"+str(j) for j in range(1,16)]
print(lst)
语法:  [结果  for循环 判断]
View Code
寻找名字中带有两个e的人的名字
names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' ,'Joe'],
         [ 'Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' , 1]]

lst = [name for line in names for name in line if type(name) == str and name.count("e") == 2]
print(lst)

# 100以内能被3整除的数的平方
# lst = [i*i for i in range(100) if i%3==0]
# print(lst)
列表推导式练习

2. 字典推导式 {k:v for循环 条件筛选}
1 [11,22,33,44] => {0:11,1:22,2:33}
2 lst = [11,22,33,44]
3 dic = {i:lst[i] for i in range(len(lst)) if i < 2} # 字典推导式就一行
4 print(dic)
5 语法:{k:v for循环 条件筛选}
6 
7 dic = {"jj": "林俊杰", "jay": "周杰伦", "zs": "赵四", "ln":"刘能"}
8 d = {v : k for k,v in dic.items()}
9 print(d)
View Code

3. 集合推导式 {k for循环 条件}
 1 s = {i for i in range(100)} # 可去除重复
 2 print(s)
 3 
 4 # 集合推导式
 5 lst = [1, 1, 4, 6,7,4,2,2]
 6 s = { el for el in lst }
 7 print(s)
 8 
 9 s = set(lst)
10 print(s)
View Code

 

三丶生成器表达式
(结果 for循环 条件)
特点:
1. 惰性机制
2. 只能向前
3. 节省内存(鸡蛋)

⽣成器表达式和列表推导式的区别:
1. 列表推导式比较耗内存. ⼀次性加载. ⽣成器表达式⼏乎不占⽤内存. 使⽤的时候才分
配和使⽤内存
2. 得到的值不⼀样. 列表推导式得到的是⼀个列表. ⽣成器表达式获取的是⼀个⽣成器

def func():
  print(111)
  yield 222
g = func() # ⽣成器g
g1 = (i for i in g) # ⽣成器g1. 但是g1的数据来源于g
g2 = (i for i in g1) # ⽣成器g2. 来源g1
print(list(g)) # 获取g中的数据. 这时func()才会被执⾏. 打印111.获取到222. g
print(list(g1)) # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了. g1 也就没有数据
print(list(g2)) # 和g1同理

深坑==> ⽣成器. 要值得时候才拿值. 

总结: 推导式有, 列表推导式, 字典推导式, 集合推导式, 没有元组推导式
⽣成器表达式: (结果 for 变量 in 可迭代对象 if 条件筛选)
⽣成器表达式可以直接获取到⽣成器对象. ⽣成器对象可以直接进⾏for循环.

def add(a, b):
  return a + b
def test():
  for r_i in range(4):
  yield r_i
g = test() 
for n in [2,  10]:
 g = (add(n, i) for i in g)
print(list(g))

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

  

 





 

posted @ 2018-08-13 15:58  心跳+  阅读(199)  评论(0编辑  收藏  举报
-->