很多Python学习者学到这里就卡住了——iter()、next()、yield、生成器表达式……这些概念绕来绕去到底有什么区别什么时候该用哪个今天一篇文章给你彻底讲透。一、先来回答一个灵魂拷问问为什么有了列表list、元组tuple这些容器还需要迭代器和生成器答因为内存。看个例子# 一个包含1亿个数字的列表nums_list[iforiinrange(100000000)]# 占用约800MB内存直接撑爆如果换成生成器# 生成器惰性计算一次只产生一个值nums_gen(iforiinrange(100000000))# 几乎不占内存这就是迭代器和生成器存在的最大意义——惰性求值Lazy Evaluation需要的时候才计算不需要的时候不占内存。二、迭代器Iterator—— 一个可以“记住遍历位置”的对象1. 什么是迭代器迭代器是一个可以记住遍历位置的对象。它从第一个元素开始访问直到所有元素被访问完结束。迭代器只能往前走不能后退。核心特点迭代器是一个对象实现了__iter__()和__next__()两个方法通过next()函数可以逐个获取元素当没有元素时抛出StopIteration异常2. 可迭代对象Iterable vs 迭代器Iterator很多初学者分不清这两个概念概念定义举例可迭代对象Iterable实现了__iter__()方法的对象可以用for循环遍历list、tuple、dict、str、set迭代器Iterator实现了__iter__()和__next__()方法的对象可以记住遍历位置iter(list)的返回值简单理解可迭代对象是“可以卖票的体育馆”迭代器是“正在排队入场的人群”。体育馆可迭代对象可以多次生成新的队伍迭代器。# 判断是否为可迭代对象 / 迭代器fromcollections.abcimportIterable,Iterator my_list[1,2,3]print(isinstance(my_list,Iterable))# True → 可迭代print(isinstance(my_list,Iterator))# False → 不是迭代器my_iteratoriter(my_list)print(isinstance(my_iterator,Iterable))# Trueprint(isinstance(my_iterator,Iterator))# True3.iter()和next()的用法iter()函数用于获取一个可迭代对象的迭代器。next()函数用于获取迭代器的下一个元素。# 基本用法my_list[10,20,30]ititer(my_list)# 获取迭代器print(next(it))# 输出: 10print(next(it))# 输出: 20print(next(it))# 输出: 30print(next(it))# 抛出 StopIteration 异常安全用法使用for循环自动捕获StopIteration异常。my_list[10,20,30]foriteminmy_list:# for 循环底层自动调用了 iter() 和 next()print(item)4. 自定义迭代器面试常考通过定义一个类实现__iter__()和__next__()方法就可以创建自定义迭代器。classCountDown:自定义迭代器从 n 倒数到 1def__init__(self,n):self.nndef__iter__(self):returnself# 迭代器返回自身def__next__(self):ifself.n0:raiseStopIteration# 必须抛出异常表示结束valueself.n self.n-1returnvalue# 使用fornuminCountDown(5):print(num)# 输出: 5, 4, 3, 2, 1三、生成器Generator—— 更优雅的迭代器1. 什么是生成器生成器是一种特殊的迭代器它使用yield关键字而不是return来返回值。核心特点生成器用yield返回值函数不会结束而是暂停并保存当前状态下次调用next()时从暂停处继续执行生成器是惰性求值的需要时才产生数据2. 创建生成器的两种方式方式一生成器函数使用yielddefcount_down(n):生成器函数从 n 倒数到 1whilen0:yieldn# 返回 n但函数暂停在这里n-1# 调用生成器函数返回一个生成器对象不会立即执行gcount_down(5)print(next(g))# 输出: 5print(next(g))# 输出: 4print(next(g))# 输出: 3print(next(g))# 输出: 2print(next(g))# 输出: 1# print(next(g)) # 抛出 StopIteration关键理解当函数执行到yield n时把n返回给调用方函数暂停在这里保存所有局部变量n的值等下次调用next(g)时从yield的下一行继续执行方式二生成器表达式# 列表推导式 vs 生成器表达式list_comp[x*2forxinrange(5)]# 列表 → 立即计算占用内存gen_exp(x*2forxinrange(5))# 生成器 → 惰性计算不占内存print(list_comp)# [0, 2, 4, 6, 8]print(gen_exp)# generator object genexpr at 0x...forvalueingen_exp:print(value)# 逐个输出: 0, 2, 4, 6, 83.yield的核心用法详解yield是生成器最重要的关键字它的核心作用可以用一句话概括yield让函数变成“可暂停、可恢复”的状态机。基本用法产生值deffibonacci(n):生成斐波那契数列的前 n 项a,b0,1count0whilecountn:yielda a,bb,ab count1fornuminfibonacci(10):print(num)# 0, 1, 1, 2, 3, 5, 8, 13, 21, 34进阶用法yield接收外部值send()方法生成器不仅可以产出值还可以接收外部传入的值defecho():生成器可以接收外部发送的值whileTrue:receivedyield# 接收外部值print(f收到:{received})gecho()next(g)# 预激活生成器执行到 yieldg.send(Hello)# 发送值给生成器 → 输出: 收到: Hellog.send(World)# 发送值给生成器 → 输出: 收到: Worldsend()和next()的区别next(g)让生成器继续执行直到遇到下一个yieldg.send(value)让生成器继续执行并把value作为当前yield表达式的返回值进阶用法yield from委托给子生成器yield from用于将迭代任务委托给另一个生成器常用于扁平化嵌套结构defsub_generator():yield1yield2yield3defmain_generator():yield开始yieldfromsub_generator()# 委托给子生成器yield结束forvalueinmain_generator():print(value)# 输出: 开始, 1, 2, 3, 结束实际应用扁平化嵌套列表defflatten(nested_list):将嵌套列表扁平化foriteminnested_list:ifisinstance(item,list):yieldfromflatten(item)# 递归委托else:yielditem nested[1,[2,3],[4,[5,6]]]forvalueinflatten(nested):print(value)# 输出: 1, 2, 3, 4, 5, 6四、迭代器 vs 生成器一张表看懂区别对比维度迭代器Iterator生成器Generator实现方式定义类实现__iter__()和__next__()使用yield关键字的函数或生成器表达式代码量较多需定义类较少函数简洁状态保存手动维护状态变量自动保存挂起时保存所有局部变量惰性求值✅ 是✅ 是内存占用极低极低能否send()传值❌ 不能✅ 能适用场景需要自定义复杂迭代逻辑大部分迭代场景更简洁推荐五、实战案例什么时候用生成器案例1读取超大文件最常见场景defread_large_file(file_path):逐行读取超大文件不一次性加载到内存withopen(file_path,r,encodingutf-8)asf:forlineinf:yieldline.strip()# 处理10GB的日志文件forlineinread_large_file(huge_log.txt):ifERRORinline:print(line)# 逐行处理内存安全案例2无限序列你不知道什么时候结束definfinite_counter():无限计数器从0开始一直数下去n0whileTrue:yieldn n1counterinfinite_counter()print(next(counter))# 0print(next(counter))# 1print(next(counter))# 2# ... 可以无限取下去不会内存溢出案例3流式处理数据管道defread_data():读取原始数据foriinrange(10):yieldideffilter_even(data_stream):过滤出偶数forvalueindata_stream:ifvalue%20:yieldvaluedefsquare(data_stream):计算平方forvalueindata_stream:yieldvalue*value# 构建处理管道读取 → 过滤偶数 → 求平方pipelinesquare(filter_even(read_data()))forresultinpipeline:print(result)# 0, 4, 16, 36, 64六、常见面试题汇总Q1return和yield有什么区别特性returnyield函数状态结束局部变量被销毁暂停局部变量被保存多次调用每次重新执行从上次暂停处继续执行返回值返回一个值函数结束返回一个值函数暂停内存效率一次性返回全部惰性生成逐个返回Q2生成器是一次性的吗是的。生成器遍历完后不能重置需要重新创建。g(xforxinrange(3))print(list(g))# [0, 1, 2]print(list(g))# [] → 已经消耗完了Q3iter()和next()的作用iter(obj)获取对象的迭代器调用对象的__iter__()方法next(it)获取迭代器的下一个元素调用迭代器的__next__()方法七、总结一张图记住所有内容可迭代对象 (Iterable) (实现了 __iter__) │ │ iter() ▼ ┌──────────────┐ │ 迭代器 (Iterator) │ │ __iter__ __next__│ └──────────────┘ │ │ next() ▼ 逐个获取元素 (惰性求值) ┌───────────────────────────────────┐ │ 生成器 (Generator) │ │ 特殊的迭代器用 yield 实现 │ │ 更简洁自动保存状态 │ └───────────────────────────────────┘ │ ┌──────────────┴──────────────┐ │ │ 生成器函数 生成器表达式 (使用 yield) (使用小括号)一句话核心记忆迭代器实现了__iter__和__next__的“状态机”生成器用yield写出来的迭代器更简单、更优雅iter()拿门票获取迭代器next()往前走一步获取下一个元素yield暂停并返回下次继续八、写在最后迭代器和生成器是Python中非常优雅的设计它们让我们可以用极低的内存消耗处理海量数据。在接口自动化测试中你可能用它来读取测试数据文件、处理分页接口的响应数据、实现流式断言等等。掌握它们你的Python水平就迈入了“进阶”的大门。