迭代器、生成器

发布时间 2023-12-13 16:08:05作者: Unlucky

【一】迭代器

迭代器(Iterator)是Python中用于遍历可迭代对象的一种机制。可迭代对象是指那些可以被迭代的对象,例如列表、元组、字符串、集合、字典。迭代器提供了一种顺序访问可迭代对象元素的方式,而不需要事先知道对象的内部结构。

迭代器是通过实现两个特殊方法来工作的:

  1. __iter__()方法:该方法返回迭代器对象本身。在迭代过程中,会首先调用可迭代对象的__iter__()方法,获取迭代器对象。

  2. __next__() 方法是迭代器对象中的一个特殊方法,它定义了在迭代过程中获取下一个元素的逻辑。

当我们使用迭代器对象进行迭代操作时,会重复调用__next__()方法来获取迭代序列中的下一个元素。每次调用该方法时,迭代器会返回序列中的下一个元素,直到序列中没有更多的元素可供迭代,此时迭代器会引发 StopIteration 异常来终止迭代。

迭代器的使用方式如下:

my_iterable = [1, 2, 3, 4, 5]  # 可迭代对象

my_iterator = iter(my_iterable)  # 获取迭代器对象

print(next(my_iterator))  # 输出:1
print(next(my_iterator))  # 输出:2
print(next(my_iterator))  # 输出:3
# ...

# 或者使用 for 循环遍历迭代器
for item in my_iterator:
    print(item)
输出结果:
1
2
3
4
5

list1 = [1, 2, 3, 4, 5]  
list2 = (list1.__iter__())  # <list_iterator object at 0x000002286570A650>  
print(list2.__next__())  # 1  
print(next(list2))  # 2  
  
  
str1 = 'dream'  
str2 = str1.__iter__()  
print(str2.__next__())  # d  
print(next(str2))  # r

通过迭代器,可以逐个访问可迭代对象中的元素,而不需要直接访问它们的索引。这在处理大型数据集或需要延迟加载元素的情况下非常有用,因为迭代器只在需要时生成下一个元素,节省了内存空间。

1.1 __iter__()

当迭代器对象调用__iter__()方法后,它会返回迭代器对象本身。在Python中,迭代器对象本身就是可迭代对象,因此调用__iter__()方法后返回的是迭代器对象本身。这是为了确保迭代器对象可以被正确地使用在需要可迭代对象的上下文中。

迭代器对象实现了__iter__()方法是为了满足可迭代对象的要求,因为可迭代对象需要提供一个返回迭代器的方法。通过返回迭代器对象本身,迭代器对象可以在需要可迭代对象的场景中使用,例如在for循环中进行迭代操作。

需要注意的是,迭代器对象本身也必须实现__next__()方法,以便能够提供下一个元素。迭代器对象的__next__()方法定义了如何获取下一个元素,而__iter__()方法则用于返回迭代器对象本身。这样,迭代器对象既可以作为可迭代对象被使用,又可以作为迭代器对象进行迭代操作。

以下是一个示例,演示了迭代器对象调用__iter__()方法后返回迭代器对象本身:

my_iterable = [1, 2, 3, 4, 5]  # 可迭代对象

my_iterator = iter(my_iterable)  # 获取迭代器对象

print(my_iterator.__iter__() is my_iterator)  # 输出:True

【二】生成器

生成器是一种特殊的迭代器,它可以通过函数的方式来创建。与常规的迭代器相比,生成器更加简洁和高效。

生成器函数使用yield语句来定义,当函数执行到yield语句时,会暂停函数的执行并返回一个值给调用者。下次调用生成器函数时,函数会从上次暂停的地方继续执行,直到再次遇到yield语句。

生成器函数可以通过循环、条件语句和其他逻辑来动态生成值,而不需要一次性生成所有的值。这种延迟生成的特性使得生成器非常适合处理大量数据或无限序列。

下面是一个简单的生成器函数的示例,演示了生成器的基本用法:

def my_generator():
    yield 1
    yield 2
    yield 3

# 创建生成器对象
gen = my_generator()

# 使用生成器对象进行迭代
for item in gen:
    print(item)

在上述示例中,my_generator() 函数是一个生成器函数,它通过使用 yield 语句来定义生成器的逻辑。每次调用生成器函数时,它会返回一个值,并在下次调用时从上次离开的地方继续执行。

生成器对象可以像迭代器一样进行迭代,因此我们可以使用 for 循环来遍历生成器对象并获取生成器生成的值。

总结来说,生成器是一种通过函数来创建的特殊迭代器,它具有延迟生成值的特性,能够高效地处理大量数据或无限序列。

2.1 yield + send 使用方式

生成器的send方法用于向生成器发送数据,并在生成器内部使用yield语句接收这些数据。它可以用来实现生成器与调用者之间的双向通信。

要使用send方法,首先需要创建一个生成器对象,然后可以使用end方法向生成器发送数据。生成器会从上一次yield语句的位置继续执行,并将发送的数据作为yield表达式的返回值。调用send方法后,生成器会暂停,直到下一次调用生成器的迭代方法(如next)或再次调用send方法。

下面是一个简单的示例,演示了如何使用send方法向生成器发送数据:

def my_generator():  
    while True:  
        received = yield  
        print('Received:', received)  
  
  
# 创建生成器对象  
gen = my_generator()  
  
# 启动生成器  
next(gen)  
  
# 使用send方法发送数据  
gen.send('Hello')  
gen.send('World')

在上述示例中,我们定义了一个生成器函数my_generator(),它使用yield语句接收数据并打印接收到的数据。我们创建了生成器对象gen,然后通过调用next(gen)启动生成器。

接下来,我们使用gen.send('Hello')gen.send('World')分别向生成器发送了两个字符串。生成器会从上一次yield语句的位置继续执行,并将发送的数据作为yield表达式的返回值打印出来。

第一次调用生成器的send方法之前必须先调用一次next(gen),用于启动生成器。此外,在生成器内部的第一个yield语句之前不能使用send方法,否则会引发TypeError