生成器和推导式

一. 推导式

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

列表推导式: lst = [i for i in range(10) if i % 2 == 0]

字典推导式: dic = {k:v for k,v in func() if k>v}    # def func():  yield 2,1  yield 3,1  yield 4,1     (yield 的第一个值不能相同, 因为字典的键会传不进去)

集合推导式: se = {i for i in range(5)}

 

a = (i for i in range(10)   # 这不是元组, 这是生成器的表达式, 具有惰性. 

 

可以用for循环, while循环, list[], tuple(), set(), 来遍历生成器

 

 

二. 生成器

生成器的本质是迭代器

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

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

超过yield的个数会报错, 但可以用try: except StopIteration兜着

 

生成器函数: 

和普通函数没有区别, 函数里面含有yield.

生成器函数在执行时, 默认不会执行函数, 而是返回生成器

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

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

f = func()拿到的是生成器, 不会执行函数. 

yield会停止执行函数, 下次再分段执行函数.

如果不使用f = func()来获取生成器, 每次用func().__next__()来获取, 每次都是获取的到第一个yield的值

def func():
    a = yield 1
    print(a)
    b = yield 2
    print(b)
    c = yield 3
    print(c)
    yield 4

f = func()
# ===================================== 第一个输出方法 ===================================== print(f.__next__()) print(f.send(123)) print(f.send(234)) print(f.send(345)) 输出 1 123 2 234 3 345 4
# ===================================== 第二个输出方法 ===================================== print(f.__next__(),f.send(123),f.send(234),f.send(345)) 输出: 123 234 345 1 2 3 4

 

生成器表达式:

gen = (i for i in range(10) if i >= 5)

gen = (func(i) for i in range(10) if i >= 5)

gen = ('xxxxx{}".format(i) for i in range(10))

 

特性:

惰性机制

只能向前

节省内存

 

题:

def func():
    print(111)
    yield 222
    yield 333

g = func()                   
g1 = (i for i in g)     # g1拿到的还生成器表达式, 不会执行表达式, 在后面的list(g1)才会执行表达式
g2 = (i for i in g)

print(list(g))          # list(g)拿到的是g的所有的yield的值, 本来g是不会自动执行的, 但是list使g 
                        # 自动执行了, g执行完了以后, g是生成器, 不能回退, 所以g1和g2再执行g的时候
                        # 就拿不到值了
print(list(g1))
print(list(g2))         # 如果g2先执行, g2就会遍历完g中的值, list又会便利完g2的值, 所以g1再遍历g 
                        # 的值, 或者list再遍历g的值就拿不到值了

 

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

def test():
    for i in range(4):
        yield i                        # yield 0,1,2,3

g = test()

for n in [2,10]
    g = (add(n, i) for i in g)         # 拿到g时不会遍历生成器
print(list(g))
 # ===================================== g的运行 =====================================
for n in [2,10]
    g = (add(n, i) for i in g)
n = 2
# g = (add(n = 2, i) for i in g)    # i的值现在拿不出来, 因为g没有被遍历, 所以add函数无法执行
                                    # 所以add函数还是add(n, i)
n = 10
# g = (add(n = 10, i) for i in (add(n = 10, i) for i in g)) # 由于add函数的n上次未执行, 
                                    # 所以add函数还是add(n, i), 所以这次n = 10时, n就被重新
                                    # 赋值了
list(g) 
# g = add(10, i) for i in (add(10, i) for i in 0.1.2.3))

 # ===================================== 改一下 =====================================d

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

def test():
    for i in range(4):
        yield i                        # yield 0,1,2,3

g = test()

for n in [2,10]
    g = [add(n, i) for i in g]  
print(list(g))
 # ===================================== g的运行 =====================================
n = 2
g = [2,3,4,5]       # 列表的推导式, 不是生成器的表达式
n = 10
g = [12,13,14,15]

 

posted @ 2018-08-13 16:54  NachoLau  阅读(572)  评论(0编辑  收藏  举报