python--生成器

本文介绍了Python中的生成器,它简化了迭代器的实现,节省内存并支持流式处理数据。通过yield关键字,生成器可以在每次迭代时暂停并返回值。yieldfrom可以组合多个可迭代对象。此外,send方法允许实现生成器内部和外部的数据通信,创建简单的协程。生成器在无限数据流和协程中有着广泛应用。
摘要由CSDN通过智能技术生成

转载:https://3yya.com/lesson/68

一、什么是生成器


在写迭代器的时候我们每次都要定义一个 class ,实现其中的 __iter____next__ 是不是略感麻烦。

之前返回一个小于等于指定值的正整数的迭代器我们就可以用生成器来这么写。

def positive(limit):
    n = 1
    while n <= limit:
        yield n
        n += 1

for n in positive(5):
    print(n)


1
2
3
4
5

是不是感觉代码量一下子缩短了一大半。

使用了 yield 的函数便是生成器。

我们来看下生成器所实现了的方法有哪些。

generator = positive(5)

print(dir(generator))


['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
 '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', 
 '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', 
 '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']

一个 生成器 对象自然而然的就包含了 __iter____next__ ,这意味着 生成器 必然就是一个 可迭代对象迭代器 。这是一个从属关系,一个 可迭代对象迭代器 不一定是 生成器

yield 关键字

我们都知道,获取 迭代器 的元素时要通过 next 方法,而 yield 关键字的作用就在于在每次执行 next 方法时,执行到 yield 的位置返回值,同时退回到 next 调用的位置继续执行。

看文字能学会代码的话我们还要键盘干嘛,来看一段代码。这个过程在交互模式下比较容易理解,需要动动手去实践一下。

def my_gen():
    print('执行一次')
    yield '第一次 yield'

    print('执行两次')
    yield '第二次 yield'

    print('执行三次')
    yield '第三次 yield'

    print('执行四次')

gen = my_gen()

image

在第一次执行 next 函数时,会从 my_gen 函数开头执行到第一个 yield 关键字,期间打印了 执行一次 ,返回了字符串 第一次 yield 到变量 result ,并回退到 next 执行的地方继续往下执行。

循环往复直到函数执行结束抛出 StopIteration 异常。

yield from 关键字

yield from 后面接一个 可迭代对象 ,等价于用 for in 去单独 yield

list1 = [1, 2, 3, 4]
list2 = ['a', 'b', 'c', 'd']

def my_gen_1():
    yield from list1
    yield from list2

def my_gen_2():
    for n in list1:
        yield n

    for n in list2:
        yield n

print('my_gen_1 循环结果:', [x for x in my_gen_1()])
print('my_gen_2 循环结果:', [x for x in my_gen_2()])


my_gen_1 循环结果: [1, 2, 3, 4, 'a', 'b', 'c', 'd']
my_gen_2 循环结果: [1, 2, 3, 4, 'a', 'b', 'c', 'd']

send 方法实现数据的双向通信

我们刚刚都还只是通过 yield 向生成器外部传值,实际上我们也可以向生成器内部传值。

def double_money():
    print('请输入你的金钱,我来负责乘2,(机会只有三次)')
    x = yield
    x = yield x * 2
    x = yield x * 2
    x = yield x * 2
double = double_money()
double.send(None)
print(double.send(10))
print(double.send(20))
print(double.send(30))

请输入你的金钱,我来负责乘2,(机会只有三次)
20
40
60

我们还可以实现一个求平均数的生成器。

def average_gen():
    count = 0
    n = yield
    while True:
        count += 1
        n += yield n / count

av = average_gen()

av.send(None)
print(av.send(10))
print(av.send(20))
print(av.send(30))


10.0
15.0
20.0

二、使用生成器的场景


由于可以使用生成器很方便地实现一个迭代器,因此迭代器适用的场景生成器几乎都适用。

  • 节省内存
  • 流式处理数据
  • 无限的数据

由于生成器可以通过 yieldsend 中断执行并双向通信,因此生成器在 python 中被用来作为 协程 的一种实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值