生成器的推导式 表达式

一  生成器

生成器的本质就是迭代器

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

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

3 其实就是手写的生成器

4 在pytion中有三种方式来获取生成器

  通过生成器函数

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

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

特点:

1 惰性机制

2只能向前

3节省内存

 

list中拿数据是全部一起拿,不是一个一个拿,里面有__next__  for 循环中也有__next__

列如:

def func():
    print("111")
    return 222     return返回一个值
ret =func()
print(ret)
结果:
111
222

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

1 def func():
2    print("111")
3    yield 222  yield 就是一个生成器函数  
4 ret =func()   形成一个生成器
5 print(ret)
结果:

<generator object func at 0X10597ff68>

通过执行_next_()来执行以下生成器

 1 def func():
 2 print("111")
 3 yield 222
 4 genner =func()   这个时候函数不会执行 而是获取生成器
 5 ret =genner.__next__()   这个时候函数才能执行 yield的作用和return一样 也是返回数据
 6 print(ret)
 7 
 8 
 9 结果:
10 111
11 222
View Code

yield是分段来执行一个函数 而return是直接停止执行函数

 1 def func():
 2 print("111")
 3 yield 222
 4 print("333")
 5 yiled 444
 6 gener =func()
 7 ret =genner._next_()
 8 print(ret)
 9 ret2=genner._next_()
10 print(ret2)
11 ret3=genner._next_()   最后一个yield执行完毕 再次_next_()程序会报错
12 print(ret3)
13 
14 
15 结果: 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
16  
View Code
 1 def func():
 2 print("111")
 3 yield 222
 4 print("333")
 5 yiled 444
 6 gener =func()
 7 ret =genner._next_()
 8 print(ret)
 9 ret2=genner._next_()
10 print(ret2)
11 ret3=genner._next_()   最后一个yield执行完毕 再次_next_()程序会报错
12 print(ret3)
13 
14 
15 结果: 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
16  
View Code

当程序运行完最后一个yield 那么后面进行_next_()程序会报错

来个实列

采购10000套学士服 直接造出来10000 一次性给完

def cloth():
lst=[]
for i in range(0,10000):
lst.append("衣服"+str(i))
return lst
c1 =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__())
8 print(cl.__next__())   一个一个取
View Code

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

接下来看send()方法 send和__next__一样都可以让生成器执行下一个yield    send()的()里面必须给定参数

 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
10 
11 gen=eat()
12 ret1=gen.__next__()
13 print(ret1)
14 ret2=grn.__next__()
15 print(ret2)
16 ret3=gen.__next__()
17 print(ret3)
18 ret4=gen.__next__()
19 print(ret4)
View Code

send和__next__()区别:

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

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

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

def func():
  print(111)
  yield 222
  print(333)
  yield 444
  print(555)
  yield 666
gen=func()
for i in gen():
print(i)

结果:
111
222
333
444
555
666

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

lst =[]
for i in range(1,15):
lst.append(i)
print(lst)

替换成列表推导式

lst=[i for i in range(1,15)]
print(lst)

例如: 从Pythion1期到pytion14期写入列表lst:

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

 我们还可以对列表中的数据进行筛选

筛选模式:

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

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

 

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

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

 打印的结果就是一个生成器,我们可以使用for循环来循环这个生成器

gen=("马化腾我第%s次爱你" % i for i in range(10))
for i in gen:
print(i)

 

二生成器函数

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

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

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

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

 

三 推导式

1 列表推导式[结果 for循环 条件筛选]

2字典推导式[k,v for循环 条件筛选}

把字典中的key和value互换
dic ={'a':1,'b':2}
new_dic={dic[key]:key for key in dic}
print(new_dic)



#在以下list中 从lst1中获取到的数据和lst2中相对应的位置的数据组成一个新字典

lst1 = ['jay', 'jj', 'sylar']
 lst2 = ['周杰伦', '林林俊杰', '邱彦涛'] 
dic ={lst1[i]:lst2[i] for i in range(len(lst1))}
print(dic)

 

3集合推导式{k for循环 条件}

集合的特点:无序,不重复  所以集合推导式自带去重的功能
lst=[1,-1,8,-8,12]
s ={abs(i) for i in lst}
print(s)

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

 

四 生成器表达式  (拿到的是一个生成器,只有执行__next__才能取值)

(结果 for循环 条件)

gen =(i for i in range(1,100) if i%3 ==0)
for num in gen:
print(num)
100以内能被3整除的数的平方
gen =(i *i for i in range(100) if i%3==0)
for num in gen:
print(num)
寻找名字中带两个e的人的名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],          ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] 

不用推导式和表达式
result=[]
for i in names:
  for name in i:
    if name.count("e") >=2:
      result.append(name)
print(result)

 

推导式
gen=(name for first in names for name in first if name.count("e") >=2)
for name in gen:
print(name)

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

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 同理

 

def add(a,b):
retern 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 16:36  茉莉花M  阅读(1554)  评论(0编辑  收藏  举报