python摸爬滚打之day12----生成器, 各种生成式

1、生成器

 生成器的本质就是迭代器.

 1.1  获取生成

  1:  生成器函数

   函数中出现 "yield" 的函数就是一个生成器函数, 再次执行函数时就不是运行函数而是获取生成器. 

  2: 生成器推导式

   ( i for i in range( 20) )  ----> 不是元组生成式, 而是生成器推导式, 它获取的是一个生成器.

        gen = ( i for i in range( 20) ), gen就是一个生成器

 1.2  生成器取值方式:  

    1,  通过__next__()取值.     2 , 通过send(" ")取值并传值.

 1 def func():
 2     print("黄焖鸡")                # 1
 3     yield "黄焖鸡yield"            # 2
 4     print("烧鸭")            # 3
 5     yield "烧鸭yield"            # 4
 6     print("蒸鹿茸")            # 5
 7     yield "蒸鹿茸yield"            # 6
 8     print("蒸熊掌")
 9 
10 gen = func()     # 函数中出现"yield" 时,表示该函数为生成器,获取生成器.
11 print(gen)     #  结果是一个生成器地址. <generator object func at 0x000002798C873C78>
12 gen.__next__()        # 取到函数体中yield的那行就停止(第1,2行),并将yield后面的内容返回给调用者
13 print(gen.__next__())       # 再次调用就从上次停止的yield下行(第3行)开始运行,截止到第四行.
14 print(gen.__next__())
15 print(gen.__next__())     # 如果yield内容结束,还继续调用,则报错,但是print("蒸熊掌")还是会继续执行的
生成器__next__()取值

 1.2  生成器本质就是迭代器, 如何满足迭代器的三个特点呢?

 1 def buy():
 2     lst = []
 3     for i in range(1000):
 4         lst.append("帽子%s" %(i))             # 把多有的帽子放在内存的列表里,占得内存大
 5     return lst
 6 print(buy())
 7 
 8 
 9 def buy_gen():
10     for i in range(1000):
11         yield "帽子%s" %(i)           # 不是一次性全部把帽子0.......帽子999放在内存,
12                                       # 而是通过__next__()一个一个取,比较省内存,但是不能往前执行,
13                                       # 满足迭代器的三个特点
14 gen = buy_gen()
15 print(gen.__next__())
16 print(gen.__next__())
17 print(gen.__next__())
18 print(gen.__next__())
如何满足迭代器的三个特点
 1 def baocaiming():
 2     print("蒸鹿茸")
 3     a = yield "蒸鹿茸yield"
 4     print("a=",a)
 5     print("蒸熊掌")
 6     b = yield "蒸熊掌yield"
 7     print("b=", b)
 8     print("烧花鸭")
 9     c = yield "烧花鸭yield"
10     print("c=", c)
11     print("烧子鹅")
12 
13 gen = baocaiming()   
14 print(gen.__next__())       # 第一次只能用__next__()取值
15 print(gen.send("a++"))      # 从上一次停止的yield开始执行,并将"a++"传给上次yield之前的变量a, a == "a++"    
16 print(gen.send("b++"))
17 print(gen.send("c++"))      # 函数里没有yield了,还继续调用,则报错,但是print("蒸熊掌")还是会继续执行的
生成器send()取值

  send()取值方式机理?

2、各种推导式

 2.1  列表推导式

  [ 结果  for循环  if条件 ]

 1 # 1到20 所有奇数的平方
 2 lst = [i**2 for i in range(20) if i % 2 == 1]
 3 print(lst)
 4 
 5 # 将 a = [3,6,9]   转化成---->   [(1,2,3),[4,5,6],[7,8,9]]
 6 print([(ele-2,ele-1,ele-0) for ele in a])
 7 
 8 # 查找名字里面有两个"e"的名字
 9 names = [
10     ['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
11     ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva'],
12 ]
13 print([r for i in names for r in i if r.count("e") == 2])
列表推导式

 2.2  字典、集合推导式

  {结果  for循环  if条件}

1 dic = {"张无忌":"赵敏", "杨过":"小龙女", "郭靖":"黄蓉"}   # 将键,值换成值,键
2 new_dic = {v:k for k,v in dic.items()}
3 print(new_dic)
4 
5 # lst = [11, 22, 33]  #  => {0:11, 1:22, 2:33}
6 lst = [11, 22, 33]
7 dic = {i:lst[i] for i in range(len(lst))}
8 print(dic)
字典推导式

 2.3  生成器推导式

   (结果  for循环  if条件)    注意: 不是元组推导式, 元组是没有推导式!

  生成器表达式和列表推导式有什么不同?

    1: 列表推导式是一次性加载完, 耗内存; 生成器表达式几乎不占内存, 只有取值时候才分配和使用内存;

    2: 列表推导式得到的是一个列表, 生成器表达式得到的是一个生成器.

 2.4  生成器的惰性机制?

 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, g2数据来源于g1
 7 # --------------------------------截至到此,还没有生成器拿过值
 8                             # 惰性机制----只要不访问就永远拿不到值
 9 print(list(g))     # ----> [222]  获取到g中的数据,此时才执行func()函数,将222返回给g.
10 print(list(g1))    # ----> []   list(g)已经将生成器g中的数据拿完了,所以g1拿不到数据,只能为[]
11 print(list(g2))    # ----> []   g2和g1一样,拿不到值.
12 
13 # list() 的机理?  (list()包含了for循环的机理)
14 #  list() ----> 包含了for循环 ----> 通过__iter__()将可迭代对象转化成了
15 #         迭代器 ----> 通过__next__()从迭代器里取值 ----> 将拿到的值添加进列表里
生成器惰性机制

 2.5  yield from

   把可迭代对象中的每一个元素作为生成器的结果返回. 

1 def gen():
2     lst = ["⿇花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
3     lst2 = ["饼铛还是微星的好", "联想不能煮鸡蛋", "微星就可以", "还可以烙饼"]
4     yield from lst          # 把 lst中的每一个元素作为生成器的结果返回给调用者.
5     yield from lst2       # 两个yield不会产生交替的效果.
6 
7 g = gen()
8 for el in g:
9     print(el)
yield from
原文地址:https://www.cnblogs.com/bk9527/p/9888818.html