Python生成器/推导式/生成器表达式

一   生成器

  生成器的本质就是迭代器

  生成器的特点和迭代器一样,取值方式和迭代器一样(__next__(),  send():  给上一个yield传值)

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

  其实就是手写的迭代器

 

1 def func():
2     print("111")
3     yield 123
4 
5 ret = func()
6 print(ret)

由于函数中含有yelid,那么这个函数就是生成器函数,  且执行这个函数的时候就不再试函数的执行了,而是获取这个生成器.

如何使用:

 

def func():
    print("111")
    yield 123
ret = func()   #这个时候函数不会被执行而是获取生成器
print(ret)       #按以前函数的方法执行会打印出地址
s = ret.__next__()
print(s)


结果
<generator object func at 0x000002EB35432C50>
111
123

 

yield     是分段执行这个函数, return    是直接停止执行这个函数

 

 

 1 def func():
 2     print(123)
 3     yield 456
 4     print(789)
 5     yield 147
 6     print(258)
 7     yield 369
 8 
 9 ret = func()
10 print(ret.__next__())
11 print(ret.__next__())
12 print(ret.__next__())
13 print(ret.__next__())    #最后一个yield 执行完毕,再次 __next__()程序会报错,  与return无关
14 
15 
16 #结果
17 123
18 456
19 789
20 147
21 258
22 369
23 Traceback (most recent call last):
24   File "E:/Python/day13/练习.py", line 48, in <module>
25     print(ret.__next__())
26 StopIteration    # 报错           

 

生成器函数:

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

2  生成器函数在执行的时候,  默认不会执行函数体,  返回生成器

3 通过生成器的__next__()  分段执行这个函数

4 send()   给上一个  yield   传值,  不能再开头(没有上一个yield)    最后一个yield  也不能用send()

 

生成器作用:

举一个例子---

比如   你比较喜欢吃鸡蛋,一次性给你买几千个鸡蛋 , 够你吃几年了,  那么这些鸡蛋你怎么存放, 需要很多地方存放,

所以这样你想吃鸡蛋了就去买一个,想吃了就买一个,是不是也能一直吃鸡蛋 

ef func():
    for i in range(1,5000):
        yield "鸡蛋"+str(i)

ret = func()
print(ret.__next__())
print(ret.__next__())
print(ret.__next__())
print(ret.__next__())
print(ret.__next__())

# 结果
鸡蛋1
鸡蛋2
鸡蛋3
鸡蛋4
鸡蛋5

区别 :  如果直接买几千个给你吃 ,  会很占地方,  在程序中就是很占内存,   然而上面的方法是  你想吃就买一个, 不会占地方  

所以   生成器非常省内存

 

send()

方法:   send()方法和__next__方法一样都可以让生成器执行到下一个yield

def func():
    print(1)
    a = yield 2
    print(a)
    b = yield 4
    print(b)
    c = yield 6
    print(c)
    d = yield 8

gen = func()
ret = gen.__next__()
print(ret)
ret1 = gen.send("")
print(ret1)
ret2 = gen.send("")
print(ret2)
ret3 = gen.send("")
print(ret3)


#结果


1
2468

 

send() 和  __next__的区别:

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

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

 

推导式:

列表推导式: 就是用一句话来生成一个列表

语法:   [结果   for循环   判断]

lis = [i for i in range(50) if i%2==1]
print(lis)

结果
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49]

 

字典推导式

语法:{k:v   for循环    条件判断}

lis = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49]
dic = {i:lis[i] for i in range(len(lis)) if i%3!=0}
print(dic)

#结果

{1: 3, 2: 5, 4: 9, 5: 11, 7: 15, 8: 17, 10: 21, 11: 23, 13: 27, 14: 29, 16: 33, 17: 35, 19: 39, 20: 41, 22: 45, 23: 47}

 

集合推导式

语法: {k  for循环    条件判断}

lis = [1,2,3,4,5,6,7,8,12,1,2,3,4,3,3,33,44,55,11,22,33,44,55,333,442,223,3,21]
set = {i for i in lis}
print(set)

#结果
{1, 2, 3, 4, 5, 6, 7, 8, 33, 11, 12, 44, 333, 21, 22, 55, 442, 223}

 

生成器表达式:

格式: (结果  for循环  条件判断)

特点:

1  惰性机制

2 只能向前

3 节省内存

 

 

重点:      面试题

def add(a,b):
    return a + b  

def test():
    for te in range(4):
        yield te

g = test()
for i in [2,10]:
    g = (add(i,n) for n in g )

print(list(g))
上面的程序详解步骤:
for i in [2,10]:
    g = (add(i,n) for n in g )
由于for循环 i = 2的时候没有取值
所以当i = 10  的时候才取值
i = 2时
g = (add(i,n) for n in g )    但是没有取值
i = 10时
g = (add(i,n) for n in (add(i,n) for n in g ) )
把i 换成10
g = (add(10,n) for n in (add(10,n) for n in g ) )

因为g 是0, 1 , 2 , 3 
所以                               10 11  12   13  
g = (add(10,n) for n in (add(10,n) for n in g ) )

g = (add(10,n) for n in (10,11,12,13) )

g = [20,21,22,23]

 

posted @ 2018-08-13 17:14  heshun  阅读(321)  评论(0编辑  收藏  举报