2018.8.13 python中生成器和生成器表达式

主要内容:

         1、生成器和生成器函数

         2、列表推导式

一、生成器

         生成器是指就是迭代器,在python中有三种方式来获取生成器:

         1、通过生成器函数

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

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

yield 和return的区别:

      yield分段来执行一个函数,break停止函数执行。

         当程序运行完最后一个yield,那么后面继续进行__next__()程序会报错。

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

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)      #结果:a =  胡辣汤    大饼
ret3 = gen.send('狗粮')
print(ret3)     #结果:b =  狗粮     韭菜盒子
ret4 = gen.send('猫粮')
print(ret4)     #结果:c =  猫粮    GAME OVER

send 和 __next__()区别:

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

      2、send可以给上一个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
for i in list(gen):
    print(i)
# 结果:
# 111
# 222
# 333
# 444
# 555
# 666

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

        首先我们先看一下这样的代码, 给出一个列表, 通过循环, 向列表中添加1-14 :

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

       替换成列表推导式:

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

       列表推导式的常用写法:

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

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

# 获取1-100内能被3整除的数
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 first in names:
for name in first:
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
    print(333)
    yield 444
    print(555)
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 333 555 [222,444]
print(list(g1))#获取g1中的数据,g1的数据来源于g,但是g已经取完了,g1也就没有数据,结果为[]
print(list(g2))#和g1同理,结果为[]

       深坑----生成器,要值得时候才拿值。

       字典推导式:

# 把字典中的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)

        集合推导式:

lst = [1, -1, 8, -8, 12]
# 绝对值去重
s = {abs(i) for i in lst}
print(s)

总结: 推导式有, 列表推导式, 字典推导式, 集合推导式, 没有元组推导式
         生成器表达式: (结果 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))

# 结果:[20, 21, 22, 23]

 

原文地址:https://www.cnblogs.com/fengchong/p/9470337.html