生成器

# 生成器函数
# 只要含有 yield 关键字的函数都是生成器函数
# yield 不能和 return 共用且需要写在函数内
# 生成器函数:执行之后会得到一个生成器作为返回值
# 生成器既含有 __next__ 方法,也含有 __iter__ 方法,所以生成器也是一个迭代器,可以使用 __next__ 方法获取下一个值,也可以通过 for 循环取值
# yield和return一样,都可以返回一个值,但是 return 在返回值之后就直接结束一个函数,而 yield 不会
def generator():
    '''含有yield,它是一个生成器函数'''
    print(1)
    yield 'a'


ret = generator()
print(ret)
print(ret.__next__())
'''
<generator object generator at 0x02FCF8D0>
1
a
'''

# 如果我想生成2000000个哇哈哈,用生成器,每生成一个,就返回一个,这样就不会出现内存不足的问题
def wahaha():
    for i in range(2000000):
        yield '哇哈哈%s' % i


g = wahaha()
for i in g:
    print(i)


# send 获取下一个值的效果和 next 基本一致

# 只是在获取下一个值的时候,给上一个 yield 的位置传递一个数据
# 使用 send 的注意事项
# 第一次使用生成器的时候 是用 next 获取下一个值
# 最后一个 yield 不能接受外部的值

def generator():
    print(123)
    content = yield 1
    print('=======', content)
    print(456)
    arg = yield 2


g = generator()
ret = g.__next__()
print('***', ret)
ret = g.send('hello')   # send的效果和next一样
print('***', ret)
'''
123
*** 1
======= hello
456
*** 2
'''
 
# 获取移动平均值
# 10 20 30 10
# 10 15 20 17.5
# avg = sum/count
def average():
    sum = 0
    count = 0
    avg = 0
    while True:
        num = yield avg
        sum += num    # 10
        count += 1    # 1
        avg = sum/count


avg_g = average()
avg_g.__next__()
avg1 = avg_g.send(10)
avg1 = avg_g.send(20)
avg1 = avg_g.send(30)
print(avg1)

 

# 预激生成器的装饰器

def init(func):   # 装饰器
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)    # g = average()
        g.__next__()
        return g
    return inner


@init
def average():
    sum = 0
    count = 0
    avg = 0
    while True:
        num = yield avg
        sum += num    # 10
        count += 1    # 1
        avg = sum/count


avg_g = average()   # ===> inner
ret = avg_g.send(10)
print(ret)
ret = avg_g.send(20)
print(ret)


# python 3 新特性

# python 2
# def generator():
#     a = 'abcde'
#     b = '12345'
#     for i in a:
#         yield i
#     for i in b:
#         yield i


# python 3
def generator():
    a = 'abcde'
    b = '12345'
    yield from a
    yield from b


g = generator()
for i in g:
    print(i)
'''
a
b
c
d
e
1
2
3
4
5
'''

 

# 生成器表达式

# 列表推导式
print([i*i for i in range(10)])
# 生成器表达式
print(i for i in range(10))
'''
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x0120FAB0>
'''

 

 # 生成器面试题

 # 面试题1

def demo():
    for i in range(4):
        yield i


# 生成器都是惰性执行的,只有要它执行的时候它才会去执行
g = demo()  # 生成器对象

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

print(list(g1))  # list(g1)把g1当中所有的内容取出来
print(list(g2))  # g1执行完之后已经空了,所以list(g2)为空列表
'''
[0, 1, 2, 3]
[]
'''

# 面试题2

def add(n, i):
    return n+i


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


g = test()
for n in [1, 10]:
    g = (add(n, i) for i in g)  # 从上到下,一直到这里,生成器都没有取过值
'''相当于
n = 1
g = (add(n, i) for i in g)

n = 10
g = (add(n, i) for i in (add(n, i) for i in test()))
这里,n = 10,而不是 n = 1,既
g = (add(10, i) for i in (add(10, i) for i in [0, 1, 2, 3]))
所以,最后结果为 [20, 21, 22, 23]
'''

print(list(g))  # 在这里,生成器才开始取值
# [20, 21, 22, 23]

 

posted @ 2018-05-20 20:56  守护窗明守护爱  阅读(248)  评论(0编辑  收藏  举报