Python 生成器

1. 什么是生成器

上篇文章讲了Python迭代器;这篇文章就来研究一下生成器。

生成器:一种特殊的迭代器,含有yield的函数就是生成器。
特殊在哪里? 生成器是一个没有手动实现__iter____next__方法的迭代器。

下属代码就是一个生成器

def func():
    x = 0
    while True:
        x += 1
        yield x**2

# 生成器的使用方式
f = func()  # func中含有yield,因此是一个生成器,同时func返回的是一个生成器对象
for i in range(10):
    ret = next(f)
    print(ret)

2. 创建生成器的方法

2.1 方法一

将列表生成式的[]换成()
如下:

n = [x for x in range(10)]
print(n)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

m = (x for x in range(10))
print(m)  # <generator object <genexpr> at 0x0000027D9AAFE660>

可以看到,m是一个生成器对象。


2.2 方法二

在函数中使用yield
如下:

def func():
    for i in range(10):
        yield i


f = func()
print(f)  # <generator object func at 0x000001ABFCEC19E0>

f也是一个生成器对象;这里要明白,当函数中含有yield的时候,python会认为它是一个生成器,因此调用函数时,会返回一个生成器对象。


3. 生成器的使用

3.1 yield的作用

yield的作用:像return一样返回一个值,然后将程序的指针停在此处,下次调用时,将从指针处继续执行。

def func():
    for i in range(10):
        yield i


f = func()
print(next(f))  # 0
print(next(f))  # 1
print(next(f))  # 2

看上述代码,每次通过next调用生成器对象时,都会继续执行for循环,因此得到的最终结果是0 1 2

但是如果使用return的话

def func():
    for i in range(10):
        return i


f = func()
print(f)  # 0
print(f)  # 0
print(f)  # 0

每次调用函数都会从开始执行,因此返回值i会不停的被覆盖成0。

yield和return的异同:
同:都会返回一个值
异:yield会暂停函数,下次调用可从暂停处继续;而return则是直接结束函数,下次调用从头开始。


3.2 调用生成器的两种方法

3.2.1 next(生成器对象)

在迭代器中,介绍过next()函数,他会调用迭代器中的__next__方法,从而进行一次值的获取。而生成器是一种特殊的迭代器,就可以理解为生成器就是迭代器。因此,生成器也可以使用next()函数进行调用。

这里重申一下next的语法:

next(迭代器对象(生成器对象))

值的注意的是,生成器返回的值是一个生成器对象,因此无法像普通函数那样调用生成器;只能使用next()函数进行调用。因此使用2.2中的生成器的方法如下

def func():
    for i in range(10):
        yield i


f = func()
print(next(f))  # 0
print(next(f))  # 1
print(next(f))  # 2

在使用next()调用生成器的时候,程序会记住yield的断点位置,每次都能够从断点处继续执行。


3.2.2 生成器对象.send(value)

上面介绍了通过next()函数调用生成器,其实也可以通过.send()调用。

send()可以完成对生成器传入值的操作,next(x)其实就等于x.send(None)

比如:

def func():
    for i in range(10):
        m = yield i
        print(m)


f = func()
print(next(f))
print(f.send('哈哈'))
print(f.send('呵呵'))

输出

0
哈哈
1
呵呵
2

注意:在首次调用生成器对象的时候,要使用next()或.send(None);如果使用send传入其他参数则程序会报错。

def func():
    for i in range(10):
        m = yield i
        print(m)


f = func()
f.send('11')

报错

TypeError: can't send non-None value to a just-started generator

4. 生成器和迭代器的异同

同:都存储了生成一组数据的方法,节省存储空间
异:生成器可以做到对程序的暂停,且在暂停后可以自动保存数据,下次继续执行时,数据不会重置;而迭代器不能暂停程序的执行,运行过程中数据的保存需要靠自己来实现。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值