yield 的作用
暂停并返回值: 当函数执行到 yield 语句时,会暂停当前函数的执行,并将 yield 后面的值返回给调用者。下次调用时,函数会从上次暂停的位置继续执行。
实现惰性求值: 生成器不会一次性生成所有数据,而是按需逐个生成,节省内存空间。
支持迭代协议: 包含 yield 的函数会自动变成生成器函数,返回一个生成器对象,该对象实现了迭代器协议(iter() 和 next() 方法)。
yield关键字和return一样会返回一个值,使用next获取返回值,如果可以返回值会报错。
def foo():
print("one")
yield "one"
print("two")
yield "two"
if __name__ == '__main__':
f = foo()
print(f)
print(next(f))
print('----')
print(next(f))
print('----')
print(next(f))

for为什么没有使用next(foo())也可以执行生成器?
在 Python 中,for 循环可以直接迭代生成器对象,而不需要显式调用 next() 函数。这是因为 for 循环内部已经实现了对生成器的自动迭代机制。
def foo():
print("one")
yield "one"
print("two")
yield "two"
if __name__ == '__main__':
f = foo()
# print(f)
# print(next(f))
# print('----')
# print(next(f))
# print('----')
# print(next(f))
for i in f:
print(i)

原因分析:
生成器的本质:
生成器是一个特殊的迭代器,它实现了 iter() 和 next() 方法。
当你调用 foo() 时,它返回一个生成器对象,而不是直接执行函数体中的代码。
for 循环的工作原理:
for 循环会自动调用生成器的 iter() 方法获取迭代器。
然后在每次循环中调用 next() 方法来获取下一个值,直到遇到 StopIteration 异常(即生成器耗尽)为止。
等价关系:
for i in foo():
print(i)
实际上等价于以下手动调用 next() 的方式:
f = foo()
try:
while True:
i = next(f)
print(i)
except StopIteration:
pass
使用场景
当需要读取大文件时,一次性加载全部内容会导致内存溢出。解释:通过 yield 逐行读取文件内容,避免将整个文件加载到内存中。yield 的核心优势在于其惰性求值特性,适用于需要高效处理大量数据或动态生成数据的场景。
def read_log(path):
with open(path, 'r') as f:
for line in f:
yield line.strip()
def count_error():
count = 0
for log_line in read_log("a.log"):
if "error" in log_line:
print(log_line)
count += 1
return count
if __name__ == '__main__':
number = count_error()
print(number)