1.迭代器
如果一个对象同时实现了iter方法和next方法,那么它就是迭代器。其中iter方法用于返回迭代器本身,而next方法则返回容器中的下一个值。当所有元素都被返回后,再执行next方法则会抛出StopIteration异常。
它是一个可以记住遍历的位置的对象。迭代器从集合的第一个元素开始访问,直到所有的元素被访问结束。迭代器只能前进,不能后退,这意味着迭代器只能进行一次完整的迭代,无法像列表一样进行无限次的反复迭代。
迭代器有两个基本方法,iter()方法和next()方法,它们分别会自行调用内部的iter方法和next方法。
迭代器主要应用于以下场景:不关心元素的随机访问,元素的个数不可提前预知。
1.1 迭代器协议
方法iter返回一个迭代器,它是包含方法next的对象,而调用这个方法时可不提供任何参数。
对象需要提供next()方法,要么返回迭代器中的下一项,要么抛出StopIteration异常,以结束迭代。
1.2 迭代器的创建
1.2.1 由可迭代对象转换生成
列表、元组等可迭代对象都可以用来创建迭代器。下面仅使用列表为例进行说明
list1 = ["西安", "上海", "苏州", "郑州", "武汉"]
iter1 = iter(list1)
print(iter1)
result:
<list_iterator object at 0x0000000001DA25E0>
13.2.2 自定义迭代器
class Fib:
"""
菲波那契数列
"""
def __init__(self, n):
self.n = n
self.current = 0
self.num1 = 1
self.num2 = 1
def __iter__(self):
return self
def __next__(self):
if self.current >= self.n:
raise StopIteration
num = self.num1
self.num1, self.num2 = self.num2, self.num1 + self.num2
self.current += 1
return num
fib = Fib(5)
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
result:
1
1
2
3
5
可以说,可迭代对象包含迭代器。所以,迭代器既可以像可迭代对象那样采用for循环进行遍历,也可以使用next()函数进行遍历。
1.3 迭代器的遍历
1.3.1 for循环遍历
for city in iter1:
print(city)
result:
西安
上海
苏州
郑州
武汉
1.3.2 next()函数遍历
while True:
try:
print(next(iter1))
except StopIteration:
break
result:
西安
上海
苏州
郑州
武汉
2.生成器
实现迭代器时,我们需要人为记录当前的迭代状态,进而根据当前的迭代状态生成下一个数据。为了达到当前记录状态,并配合next()函数进行迭代使用。我们可以使用语法更为简洁的生成器。
2.1 生成器的创建
生成器本质上是一个函数,它记住了上一次返回时在函数体的位置,也记录了程序执行的上下文。对生成器函数的第二次(或者第n次调用)时会跳转到函数上一次挂起的位置。
2.1.1 列表生成式将[]改为()
number_generator = (i for i in range(10))
print(number_generator)
result:
<generator object <genexpr> at 0x0000000001E2A3C0>
2.1.2 yield关键字
def fib(n):
current = 0
num1, num2 = 1, 1
while current < n:
num = num1
num1, num2 = num2, num1 + num2
current += 1
yield num
Fib = fib(5)
print(next(Fib))
print(next(Fib))
print(next(Fib))
print(next(Fib))
print(next(Fib))
result:
1
1
2
3
5
2.1.3 使用send方法向生成器传递参数
def generator():
start = 0
while start < 5:
tmp = yield start
print(tmp)
start += 1
f = generator()
print(next(f))
f.send('next')
f.send('23')
print(next(f))
result:
0
next
23
None
3
第一次启动生成器时使用send方法,参数只能为None
2.2 yield from关键字
可以通过yield from 可迭代对象A将A转换为生成器A
class Node:
def __init__(self, value):
self.value = value
self.children = []
def add_child(self, node):
self.children.append(node)
def __iter__(self):
return iter(self.children)
def deep_iter(self):
yield self
for i in self:
yield from i.deep_iter()
if __name__ == '__main__':
root = Node(0)
child1 = Node(1)
child2 = Node(2)
child3 = Node(3)
child4 = Node(4)
root.add_child(child1)
root.add_child(child2)
root.add_child(child3)
root.add_child(child4)
for el in root.deep_iter():
print(el.value)
result:
0
1
2
3
4