- 定义方式
- 迭代器
- 迭代器是一个实现了
__iter__()
和__next__()
方法的对象。__iter__()
方法返回迭代器对象本身,__next__()
方法用于返回迭代器的下一个元素。当没有更多元素时,__next__()
方法应该抛出StopIteration
异常。例如,可以自定义一个简单的迭代器类:
- 迭代器是一个实现了
- 迭代器
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
value = self.data[self.index]
self.index += 1
return value
可以这样使用这个迭代器:
my_iter = MyIterator([1, 2, 3])
print(next(my_iter))
print(next(my_iter))
- 生成器
- 生成器是一种特殊的迭代器,它通过
yield
关键字来返回值。生成器函数在被调用时返回一个生成器对象,函数体中的代码不会立即执行。例如:
- 生成器是一种特殊的迭代器,它通过
def my_generator(data):
for i in data:
yield i
使用方式如下:
gen = my_generator([1, 2, 3])
print(next(gen))
print(next(gen))
-
内存使用
- 迭代器
- 迭代器本身只是一个对象,它按照一定的规则逐个返回数据元素。它不会预先存储所有的数据元素,而是在每次调用
__next__()
方法时计算并返回下一个元素。这使得迭代器在处理大量数据时可以节省内存,因为不需要一次性将所有数据加载到内存中。例如,对于一个从文件中逐行读取数据的迭代器,它只需要在内存中保存当前行的数据,而不是整个文件的内容。
- 迭代器本身只是一个对象,它按照一定的规则逐个返回数据元素。它不会预先存储所有的数据元素,而是在每次调用
- 生成器
- 生成器也具有节省内存的特点。它在执行过程中,只有当
yield
语句被执行时才会生成一个值并返回,而且不会一次性生成所有可能的值。这与列表推导式形成对比,列表推导式会一次性生成一个完整的列表,可能会占用大量内存。例如,my_list = [i * 2 for i in range(1000000)]
会生成一个包含 100 万个元素的列表,而my_generator=(i * 2 for i in range(1000000))
则是按需生成值,只有在迭代时才会逐个生成元素。
- 生成器也具有节省内存的特点。它在执行过程中,只有当
- 迭代器
-
实现复杂度
- 迭代器
- 自定义迭代器需要定义一个类,并实现
__iter__()
和__next__()
方法。对于复杂的迭代逻辑,可能需要在__next__()
方法中维护一些状态信息,以确保正确地返回下一个元素。例如,在遍历一个树形结构的数据时,迭代器需要记录当前节点的位置、是否已经遍历完子节点等信息,这使得迭代器的实现可能会比较复杂。
- 自定义迭代器需要定义一个类,并实现
- 生成器
- 生成器的定义相对简单,它使用
yield
关键字在函数中返回值。生成器函数的结构更类似于普通函数,只是在需要返回值的时候使用yield
。这使得生成器的代码更简洁、直观,尤其是对于一些简单的序列生成场景,如生成斐波那契数列、自然数序列等。例如,生成斐波那契数列的生成器函数可以这样写:
- 生成器的定义相对简单,它使用
- 迭代器
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
- 用途场景
- 迭代器
- 迭代器更适合用于对自定义数据结构进行遍历,尤其是当数据结构的遍历逻辑比较复杂,或者需要与其他面向对象的设计模式相结合时。例如,在实现一个图形遍历算法(如深度优先搜索或广度优先搜索)时,可以使用迭代器来遍历图中的节点。另外,迭代器也用于对一些外部资源(如数据库查询结果集、网络流等)进行逐元素处理,因为这些资源通常不能一次性全部加载到内存中。
- 生成器
- 生成器主要用于生成序列数据,特别是在数据量较大或者数据是无限的情况下。例如,生成一个无限的自然数序列、一个按照特定规则生成的随机数序列等。生成器也常用于数据管道和协程(在 Python 中协程也是基于生成器实现的),可以方便地将数据生成、处理和消费的过程解耦,提高代码的可读性和可维护性。
- 迭代器