python 可迭代对象,迭代器,生成器

先放一张图来表示以下三者的关系:

1.生成器(generator)

为了更好的理解生成器,可以先把生成器和列表做一个比较。

理论上列表的长度是无限的,但是受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。而使用生成器也可以用来存储100万个元素。只不过生成器内部实际存储的 是一种算法,可以通过前面的元素推倒出后面的元素。这样可以大大节省内存空间。

列表可以通过列表生成式来创建,生成器可以有两种创建方式,一种是生成器表达式,一种是生成器函数(即带yield的函数,后面会讲到)。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

>>> l = [x for x in range(10)]
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> type(l)
<class 'list'>

>>> g = (x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000016DE5F3A410>
>>> type(g)
<class 'generator'>

可以看到列表生成式返回的是一个列表,而生成器表达式返回的是一个生成器。

那么如何获取生成器里面的元素的呢?如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值。

>>> next(g)
0
>>> next(g)
1
>>> next(g)
2
...

>>> next(g)
9
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

前面说过,generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。当调用next()时,实际上next()函数调用了g对象的__next__()方法,即next(g)等价于g.__next__()。

当然,实际上很少用这种方式来获取元素,可以直接用for循环,因为generator也是可迭代对象。for循环内部实际上也是调用的是g.__next__()方法,只不过已经帮我们处理了异常。

>>> for x in g:
...     print(x)
...
0
1
2
3
4
5
6
7
8
9
>>>

生成器的第二种创建方式是生成器函数,来看一个例子:

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

t = test()

print(type(t))

for j in t:
    print(j, end=" ")

## 运行结果:
<class 'generator'>
0 1 2 3 4 5 6 7 8 9

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。generator函数在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

2.迭代器(iterator)和可迭代对象(iterable)

可以直接作用于for循环的对象都叫可迭代对象。包括生成器和迭代器(生成器是迭代器的一个特例),还有str,list,tuple,set,dict等。

注意:str,list,tuple,set,dict虽然是可迭代队对象,但并不是迭代器。不过可以使用iter()函数将他们变成迭代器。当调用iter()函数时,iter()函数实际上调用了iterable的__iter__()方法。

迭代器内部都实现了__iter__()方法和__next__()方法。

from collections import Iterator, Iterable

a = "abc"
b = [1,2,3]
aa = iter(a)
bb = b.__iter__()

print(isinstance(a, Iterable))
print(isinstance(a, Iterator))

print(type(aa))
print(type(bb))

补充当用for作用于可迭代对象时,如list等,实际上是先调动list.__iter__()方法将list转换成迭代器,在调用迭代器的__next__()方法一次取出元素。

图片参考自:https://nvie.com/posts/iterators-vs-generators/

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值