Python入门——yield生成器和iter迭代器

yield生成器

yield 的作用

  • 生成器函数yield 将一个普通的函数变成一个生成器函数 。生成器函数与普通函数的区别在于,普通函数使用 return 一次性返回结果并终止,而生成器函数使用 yield 返回一个值后,会记住函数的执行状态,暂停执行,待下一次被调用时继续执行。
  • 惰性计算:生成器不会一次性生成所有结果,而是按需生成。这种方式称为"惰性计算"(lazy evaluation),非常节省内存,尤其适用于处理大数据或流式数据的场景。

yield 的工作原理

当生成器函数包含 yield 时,每次调用生成器对象的 next() 方法时,生成器会执行到 yield 语句,返回当前值并暂停。下一次调用 next() 时,生成器从上次暂停的位置继续执行,直到遇到下一个 yield 或函数结束。

基本用法

当一个函数包含 yield 关键字时,该函数不再是普通的函数,而是一个生成器函数。调用生成器函数时,它不会立即执行,而是返回一个生成器对象,允许你通过迭代的方式来逐步获取值。

示例:

python 复制代码
def simple_generator():
    print("First value:")
    yield 1  # 第一次暂停并返回值1
    print("Second value:")
    yield 2  # 第二次暂停并返回值2
    print("Third value:")
    yield 3  # 第三次暂停并返回值3

# 调用生成器函数,返回一个生成器对象
gen = simple_generator()

# 通过 next() 获取生成器中的值
print(next(gen))  # 输出: First value: 1
print(next(gen))  # 输出: Second value: 2
print(next(gen))  # 输出: Third value: 3

yieldreturn 的区别:

  • return :函数遇到 return 后,直接返回值,并终止函数的执行。
  • yield :函数遇到 yield 后,会返回一个值给调用者,同时函数的状态会被"冻结" ,即函数在 yield 处暂停,等待下一次调用时继续执行,而不是从头开始。

使用场景:

  1. 惰性求值:当处理大量数据时,生成器可以惰性计算,不必一次性将所有数据加载到内存中。
  2. 流式处理:当数据源的数据量过大,或数据是实时产生的(如读取文件、网络流等),生成器可用来逐步产生数据。
  3. 协程 :在 Python 中,yield 也被用于协程中来实现异步操作。

示例:生成一个范围内的数字

python 复制代码
def number_generator(n):
    for i in range(n):
        yield i

gen = number_generator(5)

for number in gen:
    print(number)

优点

  1. 节省内存 :相比一次性加载所有数据,生成器通过 yield 逐步生成数据,避免了占用大量内存。
  2. 效率高:适合处理大量数据或流式数据的场景,且生成器函数编写简单明了。
  3. 易于实现复杂的迭代逻辑:生成器允许在多次调用之间保存函数的执行状态,使其能够简洁地实现复杂的迭代逻辑。

总结

  • yield 关键字让你可以创建生成器函数,用于逐步生成值,而不是一次性生成所有值。
  • 生成器可以用于高效处理大量数据或实现惰性求值。

iter迭代器

在 Python 中,迭代器(Iterator)是一个可以记住遍历位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完毕后结束。迭代器只能往前走,不能回退。

迭代器的核心概念

properties 复制代码
迭代器协议: 任何实现了 __iter__()和 __next__()方法的对象都是迭代器。

__iter__(): 返回迭代器对象本身。
__next__(): 返回容器的下一个元素,直到没有元素时抛出 `StopIteration` 异常。

示例:

python 复制代码
# 自定义一个简单的迭代器
class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0  # 用来记录当前访问的位置

    def __iter__(self):
        return self  # 迭代器的 __iter__ 方法返回自身

    def __next__(self):
        if self.index < len(self.data):
            value = self.data[self.index]
            self.index += 1
            return value
        else:
            raise StopIteration  # 当没有更多元素时,抛出 StopIteration 异常

# 使用该迭代器
my_list = [1, 2, 3, 4]
my_iter = MyIterator(my_list)

for item in my_iter:
    print(item)		# 结果 1'\n' 2.. 3.. 4..
"""
解释:
这个 MyIterator 类实现了 __iter__() 和 __next__() 方法,因此它是一个迭代器。
在 for 循环中,Python 自动调用 __iter__() 方法来获取迭代器对象,并在每次循环时调用 __next__() 来获取下一个元素。
当所有元素都遍历完后,__next__() 方法抛出 StopIteration,循环就会结束。
"""

内置迭代器

Python 的许多内置数据类型都是可迭代的,比如列表、元组、字符串、字典和集合等。你可以通过 iter() 函数将这些对象转换为迭代器。

python 复制代码
my_list = [1, 2, 3, 4]
my_iter = iter(my_list)

print(next(my_iter))  # 输出: 1
print(next(my_iter))  # 输出: 2
print(next(my_iter))  # 输出: 3
print(next(my_iter))  # 输出: 4
print(next(my_iter))  # 抛出 StopIteration 异常
# Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

迭代器与可迭代对象的区别

  • 可迭代对象(Iterable) :实现了 __iter__() 方法,返回一个迭代器对象的对象。如列表、元组、字典、集合等。
  • 迭代器(Iterator) :实现了 __iter__()__next__() 方法的对象。

可迭代对象可以通过 iter() 函数得到一个迭代器,迭代器可以用 next() 函数不断获取元素直到抛出 StopIteration 异常。

迭代器的应用场景

迭代器适用于遍历数据,不要求将所有数据一次性加载到内存中,特别适合处理大量数据或流数据。

文件读取示例

python 复制代码
with open('test.txt', 'r') as file:
    for line in file:  # 文件对象是一个迭代器,每次读取一行
        print(line.strip())

总结

  • 迭代器是一种可以记住访问位置的对象,遵循迭代器协议(__iter__()__next__() 方法)。
  • 迭代器可以高效地处理数据流,避免将整个数据集一次性加载到内存中。
  • 许多内置对象都是可迭代的,并且可以通过 iter() 转换为迭代器。

相关推荐
Swift社区2 小时前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
没头脑的ht2 小时前
Swift内存访问冲突
开发语言·ios·swift
没头脑的ht2 小时前
Swift闭包的本质
开发语言·ios·swift
wjs20242 小时前
Swift 数组
开发语言
stm 学习ing3 小时前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga
湫ccc4 小时前
《Python基础》之字符串格式化输出
开发语言·python
mqiqe5 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
AttackingLin5 小时前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python