背景
看过很多篇关于迭代器和生成器的介绍,始终没有留下很深的印象。每次遇到关于迭代器和生成器的问题,还是很容易混淆,概念不清。好记性不如烂笔头,还是自己亲自整理敲一遍吧。
1. 迭代器(Iterator)
1.1 迭代器的定义和特征
定义:是一个可以记住遍历位置的对象;
特征:迭代器对象从集合的第一个元素开始访问,直到所有元素被访问完结束;
迭代器只能往前,不能后退;
具有inter()和next()方法。inter()方法返回迭代器本身;next()方法返回容器的下一个元素;
当没有下一个元素时,会抛出Stopiteration异常
字符串,列表,元组,字典都可以用于创建迭代器
调用方法:
迭代器对象可以使用for循环进行遍历
可以使用next()函数
l = [1, 2, 3, 4]
i = l.__iter__() # 等同于i = iter(l) 列表调用iter()方法返回迭代器对象i
print(i.__next__()) # 等同于print(next(i)) 输出 1
print(type(i)) # <class 'list_iterator'> 迭代器对象
p = iter(i) # 迭代器调用iter()方法
print(type(p)) # <class 'list_iterator'> 迭代器对象
print(next(i)) # 输出 2
print(next(i)) # 输出 3
print(next(i)) # 输出 4
# print(next(i)) # 抛出StopIteration异常
k = iter(l)
for t in k: # 使用for调用迭代器值,依次输出1, 2, 3, 4,不会抛出异常
print(t)
for t in k: # 因上面的for循环已经将迭代器中值取完,再次遍历,无输出
print(t)
1.2 如何通过类创建一个迭代器
把一个类作为一个迭代器使用需要在类中实现__iter__()与__next__()方法
__iter__()方法返回一个特殊的迭代器对象,这个迭代器对象实现了__next__()方法,
并通过StopIteration异常标识迭代的完成。
__next__()方法会返回下一个迭代器对象
示例:创建一个返回数字的迭代器,初始值为1,逐步递增1:
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
mynum = MyNumbers()
# myiter = iter(mynum)
myiter = mynum.__iter__()
print(type(myiter))
print(next(myiter)) # 输出 1
print(next(myiter)) # 输出 2
print(next(myiter)) # 输出 3
print(next(myiter)) # 输出 4
print(next(myiter)) # 输出 5
StopIteration异常用于标识迭代的完成,防止出现无限循环的情况,在__next__()方法中我们可以设置在完成指定循环次数后触发StopIteration异常来结束迭代
示例:在next()方法中增加StopIteration异常
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration
mynum = MyNumbers()
myiter = mynum.__iter__()
for x in myiter:
print(x) # 依次输出 1,2,3...20
2. 生成器(generator)
2.1 生成器定义
使用了yield关键字的函数被称为生成器;跟普通函数不同的是,生成器是一个返回迭代器的函数,
只能用于迭代器操作,可以理解为:生成器也是一种迭代器,在每次迭代时返回一个值,直到抛出StopIteration异常。
2.2 生成器构造
有两种构造方式
(1). 生成器表达式:和列表推导式类似,生成器表达式使用()而不是[],例如:
l = (x for x in range(5))
print(type(l)) # <class 'generator'>
for i in l: # 依次输出 0 1 2 3 4
print(i)
(2). 含有yield关键字的函数
# 含有yield关键字的函数(斐波那契数列)
def fib(n):
a, b, counter = 0, 1, 0
while True:
if counter > n:
return
yield a
a, b = b, a+b
counter += 1
f = fib(5) # f是一个迭代器对象
print(type(f)) # <class 'generator'>
for i in f:
print(i) # 依次输出 0 1 1 2 3 5
3. 可迭代对象(Iterable)
3.1 可迭代对象定义
可遍历的对象,即能够使用for循环遍历的对象。python常见的可迭代对象有:列表、元组、字符串、集合、range、字典等;生成器和迭代器也可以用for遍历,所以迭代器和生成器都是可迭代对象
3.2 判单一个对象是否为可迭代对象
直接尝试iter(object),如果没有报错,则说明object是可迭代对象
l = [1, 2, 3]
b = 3
iter(l) # 无报错
iter(b) # TypeError: 'int' object is not iterable
4. 三者之间的关系
1). 可迭代对象包含迭代器,生成器,字典等可遍历的类型数据;说明生成器和迭代器一定是可迭代对象,反之则错
2). 可迭代对象调用__iter__方法就返回一个迭代器
3). 可迭代对象无法使用next()方法
4). 迭代器和生成器都有iter和next方法,生成器是特殊的迭代器
5). 含有yield关键字的函数,这个函数其实就是生成器