python生成器

1.定义

可以像迭代器那样用for循环来获取元素的函数

2.目的

实现延时计算,缓解大量内存下内存消耗过猛的问题

3.如何创建生成器

方法一:元祖推导式

#只有元祖推导式才是生成器
(i for i in range(5))

方法二:使用yield

  • 当一个函数运行到 yield 后,函数的运行会暂停,并且会把 yield 后的值返回出去。
  • 若 yield 没有接任何值,则返回 None
  • yield 虽然返回了,但是函数并没有结束

4.生成器的使用

如何从生成器中取出元素,有如下三种方法

  1. for循环遍历
  2. next(gen)
  3. gen.send()

注意:

1.生成器在创建后并不会执行任何代码

2.gen.send(None)等价于next(gen)

5.生成器的状态

状态名含义
GEN_CREAED生成器创建,还未被激活
GEN_RUNNING解释器正在执行(只有在多线程应用中才能看到这个状态)
GEN_SUSPENDED在yield表达式处暂停
GEN_CLOSED生成器执行结束

举例

from inspect import getgeneratorstate

gen = (x for x in range(3))
print(getgeneratorstate(gen))  # GEN_CREATED
print(next(gen))  # 0
getgeneratorstate(gen)  # 'GEN_SUSPENDED'
next(gen)  # 1
next(gen)  # StopIteration

6.向生成器发送消息

def jumping_range(N):
    index = 0
    while index < N:
        # 通过send()发送的信息将赋值给jump
        jump = yield index
        if jump is None:
            jump = 1
        index += jump

if __name__ == '__main__':
    itr = jumping_range(5)
    print(next(itr))
    print(itr.send(2))
    print(next(itr))
    print(itr.send(-1))

注意:

1.jump= yield index,分成两部分:

yield index 是将index return给外部调用程序。

jump = yield 可以接收外部程序通过send()发送的信息,并赋值给jump

7.yield from

1.拼接可迭代对象

使用yield

# 字符串
astr='ABC'
# 列表
alist=[1,2,3]
# 字典
adict={"name":"wangbm","age":18}
# 生成器
agen=(i for i in range(4,8))

def gen(*args, **kw):
    for item in args:
        for i in item:
            yield i

new_list=gen(astr, alist, adict, agen)
print(list(new_list))
# ['A', 'B', 'C', 1, 2, 3, 'name', 'age', 4, 5, 6, 7]

使用yield from

# 字符串
astr='ABC'
# 列表
alist=[1,2,3]
# 字典
adict={"name":"wangbm","age":18}
# 生成器
agen=(i for i in range(4,8))

def gen(*args, **kw):
    for item in args:
        yield from item

new_list=gen(astr, alist, adict, agen)
print(list(new_list))
# ['A', 'B', 'C', 1, 2, 3, 'name', 'age', 4, 5, 6, 7]

2.生成器的嵌套

1.使用委托生成器

# 子生成器
def average_gen():
    total = 0
    count = 0
    average = 0
    while True:
        new_num = yield average
        if new_num is None:
            break
        count += 1
        total += new_num
        average = total/count

    # 每一次return,都意味着当前协程结束。
    return total,count,average

# 委托生成器
def proxy_gen():
    while True:
        # 只有子生成器要结束(return)了,yield from左边的变量才会被赋值,后面的代码才会执行。
        total, count, average = yield from average_gen()
        print("计算完毕!!\n总共传入 {} 个数值, 总和:{},平均数:{}".format(count, total, average))

# 调用方
def main():
    calc_average = proxy_gen()
    next(calc_average)            # 预激协程
    print(calc_average.send(10))  # 打印:10.0
    print(calc_average.send(20))  # 打印:15.0
    print(calc_average.send(30))  # 打印:20.0
    calc_average.send(None)      # 结束协程
    # 如果此处再调用calc_average.send(10),由于上一协程已经结束,将重开一协程

if __name__ == '__main__':
    main()

2.不使用委托生成器

# 子生成器
# 子生成器
def average_gen():
    total = 0
    count = 0
    average = 0
    while True:
        new_num = yield average
        if new_num is None:
            break
        count += 1
        total += new_num
        average = total/count
    return total,count,average

# 调用方
def main():
    calc_average = average_gen()
    next(calc_average)            # 预激协程
    print(calc_average.send(10))  # 打印:10.0
    print(calc_average.send(20))  # 打印:15.0
    print(calc_average.send(30))  # 打印:20.0

    # ----------------注意-----------------
    try:
        calc_average.send(None)
    except StopIteration as e:
        total, count, average = e.value
        print("计算完毕!!\n总共传入 {} 个数值, 总和:{},平均数:{}".format(count, total, average))
    # ----------------注意-----------------

if __name__ == '__main__':
    main()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值