python生成器与迭代器

本文介绍了Python中的生成器和迭代器概念,包括如何使用生成器节省内存空间,生成器函数的特点及其与常规函数的区别,以及如何判断一个对象是否可迭代及是否为迭代器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

python生成器与迭代器

通过列表生成式,我们可以直接创建一个列表。但是受到内存的限制,而且创建一个包含100万个元素的列表,不仅占用的内存空间,如果我们仅仅需要访问前面几个元素,那其他元素所占用的内存空间就白白浪费了。

在python中这种一边循环一边计算的机制,称为生成器。

一、生成器

列表的元素在定义的时候就放在内容中,生成器是在使用的时候采用产生。这样做的好处就是节省空间。

#列表生成式
a = [i*2 for i in range(10)]
print(a) 

通过列表创建生成器并调用

#生成器
a = (i*2 for i in range(10))
print(a)#显示的是a的内存地址
<generator object <genexpr> at 0x000001EE973CA780>

只有在被调用的时候才会生成,而且调用方法只有一个,就是通过next指令。

a = ( i*2 for i in range(10) )
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())

通过函数创建生成器,称为生生成器函数,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。(和中断的功能相似)生成器函数可以生产一个无线的序列,这样列表根本就没有办法处理。yield的作用就是把一个函数变成一个生成器,带有yield的函数不再是一个普通函数,python解释器会将其视为一个generator。

def func():
    print('first')
    yield 11111111
    print('second')
    yield 2222222
    print('third')
    yield 33333333
    print('fourth')
g=func()
print(g)
print(g.__next__())
print(g.__next__())

一个可以无穷生产奇数的生成器函数。

def odd():
    n=1
    while True:
        yield n
        n+=2
odd_num = odd()
count = 0
for o in odd_num:
    if count >=5: break
    print(o)
    count +=1

yield与return都有返回值的功能,但是return只能返回一次值,而yield可以返回多次值。

生成器支持的其他方法;

close( ):手动关闭生成器函数,后面的调用会直接返回StopIteration异常。

6
7
8
9
10
11
12
13
>>> def g4():
...     yield 1
...     yield 2
...     yield 3
...
>>> g=g4()
>>> next(g)
1
>>> g.close()
>>> next(g)    #关闭后,yield 2和yield 3语句将不再起作用
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
send( ):生成器函数最大的特点是可以接受外部传入的一个变量,并根据变量内容计算结果后返回。
def gen():
    value = 0
    while True:
        receive = yield value
        if receive == 'e':
            break
        value = 'got: %s' % receive


g = gen()
print(g.send(None))
print(g.send('aaa'))
print(g.send('e'))

执行流程:

  1. 通过g.send(None)或者next(g)可以启动生成器函数,并执行到第一个yield语句结束的位置。此时,执行完了yield语句,但是没有给receive赋值。yield value会输出初始值0注意:在启动生成器函数时只能send(None),如果试图输入其它的值都会得到错误提示信息。
  2. 通过g.send(‘aaa’),会传入aaa,并赋值给receive,然后计算出value的值,并回到while头部,执行yield value语句有停止。此时yield value会输出”got: aaa”,然后挂起。
  3. 通过g.send(3),会重复第2步,最后输出结果为”got: 3″
  4. 当我们g.send(‘e’)时,程序会执行break然后推出循环,最后整个函数执行完毕,所以会得到StopIteration异常。


二、迭代器

可直接作用于for循环的数据类型:一类是集合数据类型,如list、tuple、dict、set、str等;一类是生成器。可以直接作用于for循环的对象称为可迭代对象,Iterable。可以用isinstance()判断一个对象是否可迭代对象,如下所示:

from collections import Iterable
print(isinstance([],Iterable))
print(isinstance({ },Iterable))
print(isinstance(( ),Iterable))
print(isinstance('abc',Iterable))
print(isinstance(10,Iterable))
print(isinstance((x for x in range(10)),Iterable))

可以被next( )函数调用并不断返回下一值的对象称为迭代器:Iterator。也可以使用isinstance来判断一个对象是否是迭代对象。

from collections import Iterator
print(isinstance([],Iterator))
print(isinstance({ },Iterator))
print(isinstance(( ),Iterator))
print(isinstance('abc',Iterator))
print(isinstance(10,Iterator))
print(isinstance((x for x in range(10)),Iterator))
生成器都是Iterator对象,但List、dict、str虽然都是Iterable,但不是Iterator。把list、dict、str等可迭代对象变成迭代器可以使用iter( )函数:
print(isinstance(iter([ ]),Iterator))

三、小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

python的for循环本质上就是通过不断调用next()函数实现的。

python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,知道没有数据是抛出StopIteration错误。如果遇到了return,则直接抛出stopiteration终止迭代。

4
5
6
7
8
9
10
11
12
>>> def g2():
...     yield 'a'
...     return
...     yield 'b'
...
>>> g=g2()
>>> next(g)    #程序停留在执行完yield 'a'语句后的位置。
'a'
>>> next(g)    #程序发现下一条语句是return,所以抛出StopIteration异常,这样yield 'b'语句永远也不会执行。
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
  1. 按照鸭子模型理论,生成器就是一种迭代器,可以使用for进行迭代。
  2. 第一次执行next(generator)时,会执行完yield语句后程序进行挂起,所有的参数和状态会进行保存。再一次执行next(generator)时,会从挂起的状态开始往后执行。在遇到程序的结尾或者遇到StopIteration时,循环结束。
  3. 可以通过generator.send(arg)来传入参数,这是协程模型。
  4. 可以通过generator.throw(exception)来传入一个异常。throw语句会消耗掉一个yield。可以通过generator.close()来手动关闭生成器。
  5. next()等价于send(None)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值