python 生成器 + 生成器函数 + 推导表达式 + 生成器表达式

practice

 View Code

生成器

  生成器的本质其实就是迭代器

  生成器的特点和迭代器一样:

      取值方式和迭代器一样( __next__(), send() 可以给上一个yield传值 )

  生成器一般是由生成器函数或者生成器表达式来创建

  其实就是手写的迭代器

生成器函数

   yield 和 return 一样可以返回值

   和普通函数没有区别. 里面有yield 的函数就是生成器函数.

   生成器函数最后收尾的是yield,否则会报错 StopIterration

1 def func():
2     print("娃哈哈")
3     yield 1 # return和yield都可以返回数据
4     print("呵呵呵")
5 gen = func() # 不会执行这个函数. 获取的是生成器

    函数中如果有yield 这个函数就是生成器函数. 生成器函数() 获取的是生成器. 这个时候不执行函数

 yield: 相当于return 可以返回数据. 但是yield不会彻底中断函数. 分段执行函数.
 gen.__next__() 执行函数. 执行到下一个yield.
 gen.__next__() 继续执行函数到下一个yield. 
 1 # 普通函数
 2 def order():
 3     lst = []
 4     for i in range(100):
 5         lst.append("衣服"+str(i))
 6     return lst
 7 ll = order()
 8 print(ll)
9 # 生成器函数 10 def order(): 11 for i in range(100): 12 yield "衣服"+str(i) 13 g = order() # 获取生成器 14 f = g.__next__() #仅执行一次 遇到yield停止 15 print(f) 16 ret = g.__next__() 17 print(ret) 18 #衣服0 19 #衣服1

  __next__( ) : 执行到下一个yield,  分段执行函数

  send( )  : 执行到下一个yield, 并给上一个yield传值. 必须有参数.

       不能在开头(没有上一个yield), 最后一个yield也不可以用send()传值

def func():
    print("我是第一个段")
    a = yield 123  #第一次执行到 yield 123  但是并没有赋值给a
    print(a)
    print("石可心是第二段")
    b = yield 456
    print(b)
    print("刘伟是最后一个段")
    yield 79  # 最后收尾一定是yield

g = func()  #获取生成器, 不执行函数
print(g.__next__()) # 没有上一个yield 所以不能使用send() 开头必须是__next__()
print(g.send("煎饼果子"))
print(g.send("韭菜盒子"))
# 我是第一个段
# 123
# 煎饼果子
# 石可心是第二段
# 456
# 韭菜盒子
# 刘伟是最后一个段
# 79

练习:

def eat():
    print("我吃什么啊")
    a =  yield  "馒头"
    print("a=",a)
    b =  yield  "鸡蛋灌饼"
    print("b=",b)
    c =  yield  "韭菜盒子"
    print("c=",c)
    yield  "GAME OVER"
gen = eat()      # 获取生成器
ret1 = gen. __next__()
print(ret1) # 馒头
ret2 = gen.send("胡辣汤")
print(ret2)
ret3 = gen.send("狗粮")
print(ret3)
ret4 = gen.send( "猫粮")
print(ret4)
# 我吃什么啊
# 馒头
# a= 胡辣汤
# 鸡蛋灌饼
# b= 狗粮
# 韭菜盒子
# c= 猫粮
# GAME OVER
View Code

   for 循环 和 list( )  中自带__next__(), 因此会执行生成器函数.

def func():
    yield 1
    yield 13
    yield 26
gen = func()   #仅获取生成器, 不执行函数
for i in func(): # for的内部一定有__next__(), 因此执行函数
    print(i)    
print(list(func())) # 内部都有__next__(), 也会执行函数
# 1
# 13
# 26
# [1, 13, 26] 

推导式     (列表  字典  集合)

普通生成列表用for 循环
lst=[] for i in range(1,5): lst.append('python'+str(i)) print(lst) # ['python1', 'python2', 'python3', 'python4']

   1) 列表推导式 : [结果  for 循环  条件筛选]   一句话生成列表

lst = ["python"+str(j) for j in range(1,5)]
print(lst)
# ['python1', 'python2', 'python3', 'python4']

# 求奇数列表
lst = [i for i in range(20) if i%2==1]
print(lst)
#[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

# 100以内能被3整除的数的平方
lst = [i*i for i in range(20) if i%3==0]
print(lst)
#[0, 9, 36, 81, 144, 225, 324]

# 寻找名字中带有两个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)
#['Jefferson', 'Wesley', 'Steven', 'Jennifer']

   2) 字典推导式 : {k:v  for 循环  条件筛选}

# [11,22,33,44] ==>> {0:11,1:22}  列表转为字典,只要前两个
lst = [11,22,33,44]
dic = {i:lst[i] for i in range(len(lst)) if i < 2} # 字典推导式就一行
print(dic)
#{0: 11, 1: 22}

dic = {"jj": "林俊杰", "jay": "周杰伦", "zs": "赵四", "ln":"刘能"}
d = {v : k for k,v in dic.items()}  #k,v 互换
print(d)
# {'林俊杰': 'jj', '周杰伦': 'jay', '赵四': 'zs', '刘能': 'ln'}

    3) 集合推导式 : {k  for 循环  条件筛选}

     可用于去重 

s = {i for i in range(100)} 
print(s)

lst = [1, 1, 4, 6,7,4,2,2]
s = { el for el in lst }  # 可去除重复
print(s)

s = set(lst) #等价于
print(s) 

生成器表达式  

   特点 :

    1. 惰性机制

    2. 只能向前

    3. 节省内存

  语法 :   (结果   for 循环  条件筛选)       外面是小括号

# 生成器表达式 (元组)
tu = (i for i in range(10)) #没有元组推导式,
print(tu)  #是个生成器
#<generator object <genexpr> at 0x000002A4A48D0E60>
print(tu.__next__())  # 0
print(tu.__next__())  # 1
print(tu.__next__())  # 2

 

def func():
    print(111)
    yield 222
    yield 333
g = func()   # 获取生成器
g1 = (i  for i in  g) # 生成器
g2 = (i  for i in  g1) # 生成器
print(list(g)) # 为[222,333] 源头. 从源头把数据拿走了
print(list(g1)) # 为[] 这里执行的时候. 源头已经没有数据
print(list(g2)) # 为[] 这里也没有值了
# 111
# [222, 333]
# []
# []

 

重点分析:
def
add(a,b): return a+b def test(): for i in range(4): yield i g = test() #获取生成器 # 以下拆开部分等价于for 循环中的部分 # n = 1 # g = (add(n, i) for i in g) #只是生成器没有拿值 # n = 10 # g = (add(n, i) for i in g) #只是生成器没有拿值 # n = 5 # g = (add(n, i) for i in g) #只是生成器没有拿值 for n in [1,10,5]: #循环3次 最后一次的 g = (add(n,i) for i in g) #等价于: g = (add(n,i) for i in (add(n,i) for i in (add(n,i) for i in g))) print(list(g)) #这时候才取值, 循环3次,最后一次n取值为5, 前两次循环也带入5计算 print(list(g)) #为[] 因为前面的list取完了,g中即test()源头中没有数据了 # [15, 16, 17, 18] # []

 

g=test()
for n in [1,10,5]:  #循环3次 最后一次的
    g = (add(n,i) for i in g)
    print(list(g))  #等于 1 的时候取值,取完了后面的都为空
# [1, 2, 3, 4]
# []
# []

 

posted @ 2018-08-13 14:51  葡萄想柠檬  Views(131)  Comments(0)    收藏  举报
目录代码