迭代器与生成器


迭代器与生成器

1. 迭代器

迭代器是实现了迭代器协议的对象,这一协议包含 __iter__()__next__() 方法。__iter__() 方法返回迭代器对象本身,而 __next__() 方法返回迭代器的下一个值。若没有更多值,就会抛出 StopIteration 异常。

Python 有许多内置函数可以返回迭代器,例如 range()enumerate()zip() 等。

要创建一个迭代器,需要定义一个类,该类包含 __iter__()__next__() 方法。

示例代码

# 自定义迭代器类
class MyRange:
    def __init__(self, start, end):
        self.start = start
        self.end = end
        self.current = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.end:
            value = self.current
            self.current += 1
            return value
        else:
            raise StopIteration


# 使用自定义迭代器
my_range = MyRange(0, 5)
for num in my_range:
    print(num)

代码解释

  1. __init__ 方法:对迭代器的起始值、结束值和当前值进行初始化。
  2. __iter__ 方法:返回迭代器对象本身。
  3. __next__ 方法:返回迭代器的下一个值,若没有更多值,就抛出 StopIteration 异常。
  4. 使用 for 循环遍历迭代器for 循环会自动调用迭代器的 __iter__()__next__() 方法。

1.iter() 方法

iter() 是 Python 的内置函数,其作用是把一个可迭代对象(像列表、元组、字符串等)转变为迭代器对象。迭代器是一种支持 __next__() 方法的对象,借助该方法可以逐个访问可迭代对象里的元素。

语法

iter(object[, sentinel])
  • object:这是要转换为迭代器的可迭代对象。
  • sentinel(可选):若提供了 sentinel 参数,object 就必须是可调用对象(如函数),此时 iter() 会创建一个迭代器,每次调用迭代器的 __next__() 方法时,都会调用 object,直到返回值等于 sentinel 为止。

示例

my_list = [1, 2, 3, 4, 5]
my_iterator = iter(my_list)
print(type(my_iterator))  # 输出: <class 'list_iterator'>

2.next() 方法

next() 同样是 Python 的内置函数,它用于从迭代器中获取下一个元素。当迭代器中没有更多元素时,会抛出 StopIteration 异常。

语法

next(iterator[, default])
  • iterator:这是要从中获取元素的迭代器对象。
  • default(可选):若提供了 default 参数,当迭代器耗尽时,会返回 default 值,而不会抛出 StopIteration 异常。

示例

my_list = [1, 2, 3, 4, 5]
my_iterator = iter(my_list)

try:
    print(next(my_iterator))  # 输出: 1
    print(next(my_iterator))  # 输出: 2
    print(next(my_iterator))  # 输出: 3
    print(next(my_iterator))  # 输出: 4
    print(next(my_iterator))  # 输出: 5
    print(next(my_iterator))  # 抛出 StopIteration 异常
except StopIteration:
    print("迭代器已耗尽")

结合使用

iter()next() 方法通常结合使用,以实现对可迭代对象的手动迭代。下面是一个完整的示例:

my_list = [1, 2, 3, 4, 5]
my_iterator = iter(my_list)

while True:
    try:
        element = next(my_iterator)
        print(element)
    except StopIteration:
        break

在这个示例中,先使用 iter() 函数把列表转换为迭代器,然后利用 next() 函数逐个获取迭代器中的元素,直至迭代器耗尽,捕获 StopIteration 异常并终止循环。

迭代器的优势

  • 节省内存:迭代器在需要时才生成元素,无需一次性将所有元素存储在内存中。
  • 惰性求值:只有在调用 __next__() 方法时才会计算下一个元素,这在处理大规模数据时非常有用。

迭代器的应用场景

  • 循环遍历:迭代器最常见的用途是在 for 循环中遍历元素。
  • 数据处理:在处理大规模数据时,可以使用迭代器逐个处理元素,避免内存溢出。

2.生成器

在 Python 里,生成器是一种特殊的迭代器,能够一边迭代一边生成元素,而不用事先把所有元素都存储在内存里。这种特性让生成器在处理大规模数据或者无穷序列时极为高效。下面会详细介绍 Python 生成器的定义、使用、工作原理等内容。

在 Python 中,有两种方式可以定义生成器:生成器函数和生成器表达式。

1. 生成器函数

生成器函数是带有 yield 关键字的普通函数。当函数被调用时,它不会立即执行,而是返回一个生成器对象。每次调用生成器的 __next__() 方法(在 Python 中也可以使用 next() 函数),函数会执行到下一个 yield 语句处,返回 yield 后面的值,并暂停执行。下一次调用 __next__() 方法时,函数会从上次暂停的地方继续执行。

def my_generator():
    yield 1
    yield 2
    yield 3

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

# 使用 next() 函数获取生成器的下一个值
print(next(gen))  # 输出 1
print(next(gen))  # 输出 2
print(next(gen))  # 输出 3

# 当生成器没有更多值时,会抛出 StopIteration 异常
try:
    print(next(gen))
except StopIteration:
    print("生成器已耗尽")

2. 生成器表达式

生成器表达式类似于列表推导式,不过它使用圆括号而不是方括号。生成器表达式返回一个生成器对象,它会逐个生成元素,而不是一次性生成所有元素。

# 生成器表达式
gen_expr = (x * 2 for x in range(5))

# 遍历生成器表达式
for num in gen_expr:
    print(num)

3. 生成器的工作原理

生成器的工作原理基于 Python 的迭代协议。生成器对象实现了 __iter__()__next__() 方法,因此可以被迭代。当调用 next() 函数时,生成器会执行到下一个 yield 语句,返回 yield 后面的值,并暂停执行。当再次调用 next() 函数时,生成器会从上次暂停的地方继续执行,直到遇到下一个 yield 语句或者函数结束。

生成器的优点

  • 节省内存:生成器逐个生成元素,不需要一次性存储所有元素,因此在处理大规模数据时可以显著节省内存。
  • 惰性求值:生成器只有在需要时才会生成元素,这种惰性求值的特性可以提高程序的效率。

生成器的应用场景

  • 处理大规模数据:当处理大规模数据集时,使用生成器可以避免将所有数据加载到内存中,从而节省内存。
  • 无穷序列:生成器可以用来表示无穷序列,例如斐波那契数列。
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# 创建斐波那契数列生成器
fib_gen = fibonacci()

# 输出前 10 个斐波那契数
for _ in range(10):
    print(next(fib_gen))

4. 生成器的方法

除了 __next__() 方法外,生成器还提供了一些其他的方法,例如 send()throw()close()

  • send(value):用于向生成器发送一个值,并继续执行生成器。
  • throw(type[, value[, traceback]]):用于在生成器内部抛出一个异常。
  • close():用于关闭生成器,停止生成元素。
def counter():
    num = 0
    while True:
        received = yield num
        if received is not None:
            num = received
        else:
            num += 1

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

# 获取第一个值
print(next(gen))  # 输出 0

# 发送一个值给生成器
print(gen.send(10))  # 输出 10

# 继续获取下一个值
print(next(gen))  # 输出 11

# 关闭生成器
gen.close()

# 尝试获取下一个值,会抛出 StopIteration 异常
try:
    print(next(gen))
except StopIteration:
    print("生成器已关闭")

0 条评论

发表评论

暂无评论,欢迎发表您的观点!