1.什么是迭代器?
在说迭代器前,先说可迭代(Interable)。比如,列表、元组、字典已经字符串都是可以迭代的,我们可以用collections中引入Iterable来判断。
from collections import Iterable
print(isinstance([1,2,3],Iterable)) #True
如何判断是不是迭代器呢?可以用Iterator来判断,输出结果是False,列表可迭代,但不是迭代器。
from collections import Iterator
print(isinstance([1,2,3],Iterator)) #False
那怎么把可迭代序列变成迭代器呢?又怎么访问迭代器中的元素呢?
#使用iter()把列表转换成迭代器
lst = [1, 2, 3]
lst_iter = iter(lst)
print(isinstance(lst_iter, Iterator)) #True
#访问迭代器中的元素
#尝试用列表下表的方式访问迭代器中的值,可以看到报错
print(lst_iter[0]) #TypeError: 'list_iterator' object is not subscriptable
#用next()和for语句
print(next(lst_iter)) #1
最后,来总结一下,什么是迭代器?以及它的两个基本方法。
迭代器是访问集合元素的一种方式,是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()
2.什么是生成器?
在此之前先回顾一下推导式,其中最常见的是列表列表推导式,列表推导式代码如下,可以看到lst是列表类型。
lst = [i for i in range(5)]
print(lst,type(lst)) #打印结果: [0, 1, 2, 3, 4]
如果我们把上面的[ ]换成( ),输出结果是应该是什么呢?是元组推导式?
lst = (i for i in range(5))
print(lst,type(lst)) #打印结果: at 0x000001CC28F48150>
从运行的结果看,有两点不同。第一,没有向上面列表推导式一样直接打印出数字序列;第二,类型也从list变成了generator,generator也就是生成器。
yield关键字
此外,在使用了yield关键字的函数也称为生成器。与普通函数相比,生成器是返回迭代器的函数。同时,生成器也是一种特殊的迭代器。所以,我们也可以像迭代器一样使用next()和for来获取生成器中的元素。
def myG():
for i in range(3):
print('before yield')
yield i
print('after yield')
g = myG()
print(next(g))
#运行结果分别是:
#before yield
#0
从执行结果可以看出两点:第一,执行一次next(g),打印了before yield和0,可以知道函数运行到了yield i 这一行。第二,yield i 这一行返回了i的值,yield i作用类似于return i。与return不同的是,return后面的代码不再执行,yield后面的代码在一下次访问的时候接着执行。
def myG():
for i in range(3):
print('before yield')
yield i
print('after yield')
g = myG()
print(next(g))
print(next(g))
#运行结果分别是:
#before yield
#0
#after yield
#before yield
#1
#打印生成器
print(g) #
执行两次next(),运行结果与第一次对比,多了3行输出。可以看到,第二次执行next()时,函数从yield i后面继续执行,并在下一次循环后又停留在了yield i处。
可以发现,生成器并不能直接用print()输出其中的元素,需要用next()或者for来访问时才输出。所以,生成器可以用于节省内存空间,因为它是在访问时才使用,可以在交互式环境下比较两者的区别(运行前注意保存文件)。
a = [i for i in range(10**20)]
b = (i for i in range(10**20))