返回

从头到尾理解迭代器与生成器

前端

以前没有接触到迭代器和生成器,只觉得是高端名词。但现在它们已经是切图 仔必备的工具。这篇文章将对这两个概念进行深入浅出的讲解,帮助你彻底搞懂它们。

迭代器

首先来介绍一下迭代器。迭代器其实是一种对象,它可以让你遍历集合中的元素。比如一个列表,你可以用 for 循环来遍历它的元素:

my_list = [1, 2, 3, 4, 5]

for item in my_list:
  print(item)

上面的代码会依次打印出列表中的每个元素。这是因为列表实现了迭代器接口,它内部有一个方法叫 __iter__,这个方法返回一个迭代器对象。当你在列表上执行 for 循环时,实际上是在调用这个方法来获取迭代器对象,然后用迭代器对象来遍历列表中的元素。

迭代器对象提供了两个方法:__next____iter____next__ 方法返回集合中的下一个元素,__iter__ 方法返回迭代器对象本身。这两个方法是迭代器协议的一部分,如果你想让你的类实现迭代器接口,就需要实现这两个方法。

生成器

生成器是一种特殊类型的迭代器,它允许你在需要的时候生成元素。与列表不同,生成器不会一次性创建所有元素,而是只在需要的时候才创建。这使得生成器非常适合处理大数据集,因为你不需要一次性加载整个数据集到内存中。

要创建一个生成器,你只需要使用 yieldyield 关键字可以让你暂停生成器的执行,并在需要的时候继续执行。举个例子,下面的代码创建一个生成器,它生成斐波那契数列:

def fibonacci():
  a, b = 0, 1
  while True:
    yield a
    a, b = b, a + b

fib = fibonacci()

for i in range(10):
  print(next(fib))

上面的代码中,fibonacci 函数返回一个生成器对象。这个生成器对象内部有一个 while 循环,它不断生成斐波那契数列的元素。当你在生成器对象上执行 for 循环时,实际上是在调用 __next__ 方法来获取生成器中的下一个元素。

迭代器和生成器的应用场景

迭代器和生成器在编程中有很多应用场景。比如:

  • 遍历集合: 迭代器和生成器都可以用来遍历集合中的元素。
  • 处理大数据集: 生成器非常适合处理大数据集,因为你不需要一次性加载整个数据集到内存中。
  • 惰性计算: 生成器可以实现惰性计算,这意味着只有在需要的时候才计算元素。这可以节省大量的内存和时间。
  • 协程: 迭代器和生成器可以用来实现协程。协程是一种轻量级的多任务处理机制,它允许你在不同的任务之间切换,而不需要创建新的线程或进程。

迭代器和生成器的优缺点

迭代器和生成器各有优缺点。

迭代器的优点:

  • 易于实现:迭代器很容易实现,只需要实现 __iter____next__ 这两个方法。
  • 兼容性好:迭代器与大多数编程语言兼容。
  • 内存效率高:迭代器只在需要的时候才创建元素,因此非常节省内存。

迭代器的缺点:

  • 只能向前遍历:迭代器只能向前遍历,不能向后遍历。
  • 不能修改集合:迭代器不能修改集合中的元素。

生成器的优点:

  • 可以惰性计算:生成器可以实现惰性计算,这意味着只有在需要的时候才计算元素。
  • 可以双向遍历:生成器可以双向遍历,既可以向前遍历,也可以向后遍历。
  • 可以修改集合:生成器可以修改集合中的元素。

生成器的缺点:

  • 实现复杂:生成器比迭代器更难实现。
  • 兼容性差:生成器与一些编程语言不兼容。
  • 内存效率低:生成器比迭代器更耗费内存,因为生成器需要存储生成器状态。

总结

迭代器和生成器是编程中常用的数据结构,它们各有优缺点。迭代器易于实现,兼容性好,内存效率高,但只能向前遍历,不能修改集合。生成器可以惰性计算,可以双向遍历,可以修改集合,但实现复杂,兼容性差,内存效率低。