生成器和生成器表达式

# 生成器本质就是迭代器
# 第一种方法通过函数来获取生成器

def fun1():
    print('111')
    yield '222'
    print('333')
    yield '444'


g = fun1()
# 函数不会执行而是获取生成器
print(g)
# fun1是生成器函数,而g就是生成器 <generator object fun1 at 0x000001D1E2F1B3C8>
print(g.__next__())
print(g.__next__())
# 当执行nextAPI的时候函数才会执行,yield是返回值
# yield和return都是来返回值区别是什么?yield是分段执行函数而return是直接停止函数
# 函数生成器可以使用send方法传值
def fun2():
    a = yield '222'
    print('a=',a)
    b = yield '444'
    print('b=',b)
    yield '666'

g = fun2()
print(g.__next__())
print(g.send('首次传值'))
print(g.send('二次传值'))

# 222
# a= 首次传值
# 444
# b= 二次传值
# 666

# 打印结果,send同样是执行下一段代码,这里next执行的时候,代码到yield '222'停止运行
# yield返回值并且终止一段代码,到send执行a = 赋值
# 列表推导式
lst  = ['三年级%s班' %i for i in range(1,8)]
# print(lst)
# ['三年级1班', '三年级2班', '三年级3班', '三年级4班', '三年级5班', '三年级6班', '三年级7班']
# 相当于
lst = []
for i in range(1,8):
    lst.append('三年级%s班' %(i))
print(lst)

# 生成器推导式
gen = ('返回值是%s' %(i) for i in range(1,15) if i % 3 == 0)
# 在推导式中可以用if进行筛选
# 相当于

def fun3():
    for i in range(1,15):
        if i %3 == 0:
            yield '返回值是%s' %(i)

gen1 = fun3()
print(list(gen))
print(list(gen1))
# ['返回值是3', '返回值是6', '返回值是9', '返回值是12']
# 我们将生成器变成列表后的结果,两次结果相同
# 生成器只有在要值的时候才会取值,且生成器的next指针只能向下取值,也就是只能取一次值
def fun4():
    print(111)
    yield 222

g = fun4()

g1 = (i for i in g)
g2 = (i for i in g1)

print(list(g))
print(list(g1))
print(list(g2))

# 111
# [222]
# []
# []
# 打印的结果,因为fun4是生成器函数,只有在取值的时候才会执行,list(g),将生成器转换为列表,这时候需要取值
# 所以执行了生成器函数,并且将返回值222取出,这时候生成器中就没有值了,也就是next指针无法向下继续走了,所以g2,g3都是空

# 字典推导式
dic = {i - 1:i for i in [1,2,3,4,5,6] if i %2 == 0}
print(dic)

# 集合推导式

lst = [1,2,3,4,5,5,6,6]
s = {i for i in lst}
print(s)
# 集合推导式,去重
def add(a,b):
    return a + b

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

g = test()

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

print(list(g))

#结果 [10, 11, 12, 13]

# 首先在利用生成器函数获得一个生成器
# 这个时候执行循环,我们知道生成器的惰性机制,只有在next和send的取值时候才会执行
# 所以这时候for循环执行的时候生成器不会执行
# 这个时候我们debug一下
# test() = <generator object test at 0x000001C8142DDEC8>
# 当循环执行完一遍后我们发现生成器的内存地址发生了变化<generator object <genexpr> at 0x000001C814A57448>
# 因为生成器表达式的惰性机制他没有取值操作,但却进行了表达式的置换简单来说当循环结束后表达式
g = (add(n , i) for i in (add(n ,i) for i in test()))
# 生成器没有取值,但却会不停的嵌套,当你运行next的时候才会进行取值,循环结束后n = 5
# print(g.__next__()) result:10,这个地方for循环是个烟雾弹,在执行for循环的时候生成器不停的嵌套但却不会真正运算或者取值
# 这也是生成器性能高的地方

 

posted on 2019-10-16 22:45  素心~  阅读(231)  评论(0编辑  收藏  举报

导航