当前位置: 首页 > news >正文

Python 迭代器与生成器专项练习:6 道编程题从入门到精通

配套专栏:Python 全栈修炼之路 第 13 篇《迭代器与生成器——惰性求值的艺术》

难度分布:⭐ → ⭐⭐ → ⭐⭐ → ⭐⭐⭐ → ⭐⭐⭐ → ⭐⭐⭐⭐

核心覆盖__iter__/__next__yield、生成器表达式、itertoolsyield from、协程通信


前言

第十三篇是进阶修炼篇的开篇,核心主题是惰性求值——用最少的内存处理最多的数据。本练习精选 6 道编程题,从自定义迭代器到协程管道,层层递进,帮你彻底掌握迭代器与生成器的精髓。


题目一:自定义迭代器——倒计时与步进器 ⭐

📌 题目描述

实现两个自定义迭代器类,手动实现__iter____next__协议:

# 倒计时迭代器cd=CountDown(5)print(list(cd))# [5, 4, 3, 2, 1]# 步进迭代器(支持任意步长和方向)step=Stepper(0,10,2)print(list(step))# [0, 2, 4, 6, 8, 10]step2=Stepper(10,0,-3)print(list(step2))# [10, 7, 4, 1]# 迭代器只能遍历一次cd2=CountDown(3)print(list(cd2))# [3, 2, 1]print(list(cd2))# [](已耗尽)

💡 编程思路

这道题考察迭代器协议__iter__返回self__next__产生下一个值或抛出StopIteration

  1. CountDown:内部维护一个计数器self.current,每次__next__返回当前值并递减,到 0 时抛出StopIteration
  2. Stepper:支持startstopstep三个参数,类似range()但作为类实现。需要处理正步长和负步长两种情况。
  3. 一次性特性:迭代器耗尽后再次遍历返回空列表,这是迭代器与可迭代对象的核心区别。

🖥️ 参考代码

fromcollections.abcimportIteratorclassCountDown:"""倒计时迭代器:从 start 倒数到 1。"""def__init__(self,start:int):ifstart<0:raiseValueError("start 必须为非负整数")self.current=startdef__iter__(self)->"CountDown":returnselfdef__next__(self)->int:ifself.current<=0:raiseStopIteration value=self.current self.current-=1returnvaluedef__repr__(self)->str:returnf"CountDown({self.current})"classStepper:"""步进迭代器:类似 range(),但以迭代器协议实现。"""def__init__(self,start:int,stop:int,step:int=1):ifstep==0:raiseValueError("step 不能为 0")self.start=start self.stop=stop self.step=step self.current=start self._exhausted=Falsedef__iter__(self)->"Stepper":returnselfdef__next__(self)->int:ifself._exhausted:raiseStopIterationifself.step>0andself.current>self.stop:self._exhausted=TrueraiseStopIterationifself.step<0andself.current<self.stop:self._exhausted=TrueraiseStopIteration value=self.current self.current+=self.stepreturnvaluedef__repr__(self)->str:returnf"Stepper({self.start},{self.stop},{self.step})"classRepeater:"""重复元素迭代器:无限重复指定元素 n 次。"""def__init__(self,value,times:int):self.value=value self.times=times self.count=0def__iter__(self):returnselfdef__next__(self):ifself.count>=self.times:raiseStopIteration self.count+=1returnself.value# 测试if__name__=="__main__":print("=== CountDown ===")cd=CountDown(5)print(f"类型:{type(cd)}")print(f"是迭代器:{isinstance(cd,Iterator)}")print(f"遍历:{list(cd)}")print(f"再次遍历:{list(cd)}# 已耗尽")print("\n=== Stepper ===")print(f"正步长:{list(Stepper(0,10,2))}")print(f"负步长:{list(Stepper(10,0,-3))}")print(f"单元素:{list(Stepper(5,5,1))}")print("\n=== Repeater ===")print(f"重复 5 次:{list(Repeater('Hello',5))}")print("\n=== for 循环兼容 ===")foriinCountDown(3):print(f" 倒计时:{i}")print("\n所有测试通过 ✓")

🔗 关联知识点

知识点说明
__iter__返回迭代器自身
__next__返回下一个值或StopIteration
迭代器一次性耗尽后不可复用
isinstance(obj, Iterator)迭代器类型检查
for循环原理自动调用iter()next()

题目二:生成器函数——斐波那契与素数 ⭐⭐

📌 题目描述

使用yield实现两个经典数学序列生成器:

# 斐波那契数列(前 N 个)fibs=list(fibonacci(10))print(fibs)# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]# 无限斐波那契 + islice 截取fromitertoolsimportisliceprint(list(islice(fibonacci_infinite(),8)))# [0, 1, 1, 2, 3, 5, 8, 13]# 素数生成器(前 N 个)primes=list(prime_generator(10))print(primes)# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]# 无限素数 + takewhile 截取fromitertoolsimporttakewhileprint(list(takewhile(lambdax:x<50,prime_infinite())))# [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]# 内存对比importsys fib_list=[fibonacci(100000)]# 大量内存fib_gen=fibonacci(100000)# 几乎不占内存print(f"列表:{sys.getsizeof(list(fibonacci(1000)))}bytes")print(f"生成器:{sys.getsizeof(fibonacci(1000))}bytes")

💡 编程思路

这道题考察yield惰性求值 + 无限序列 + itertools 截取

  1. 有限斐波那契yield每次产生一个数,用count控制数量。
  2. 无限斐波那契while True+yield,永不停止,配合islice截取。
  3. 素数生成器:维护一个素数列表,用试除法判断新数是否为素数。
  4. 内存优势:生成器不存储所有值,只在需要时计算,适合大数据量。

🖥️ 参考代码

importsysimporttimefromitertoolsimportislice,takewhiledeffibonacci(n:int):"""生成前 n 个斐波那契数(有限生成器)。"""a,b=0,1for_inrange(n):yielda a,b=b,a+bdeffibonacci_infinite():"""无限斐波那契数列生成器。"""a,b=0,1whileTrue:yielda a,b=b,a+bdefprime_generator(n:int):"""生成前 n 个素数。"""primes=[]candidate=2whilelen(primes)<n:is_prime=Trueforpinprimes:ifp*p>candidate:breakifcandidate%p==0:is_prime=Falsebreakifis_prime:primes.append(candidate)yieldcandidate candidate+=1defprime_infinite():"""无限素数生成器。"""primes=[]candidate=2whileTrue:is_prime=Trueforpinprimes:ifp*p>candidate:breakifcandidate%p==0:is_prime=Falsebreakifis_prime:primes.append(candidate)yieldcandidate candidate+=1defcollatz(start:int):"""考拉兹猜想(冰雹猜想)序列生成器。"""n=startwhilen!=1:yieldnifn%2==0:n=n//2else:n=3*n+1yield1# 测试if__name__=="__main__":print("=== 斐波那契(有限) ===")print(f"前 10 个:{list(fibonacci(10))}")print(f"前 20 个:{list(fibonacci(20))}")print("\n=== 斐波那契(无限 + islice) ===")print(f"第 5~15 个:{list(islice(fibonacci_infinite(),5,15))}")print("\n=== 素数生成器 ===")print(f"前 10 个素数:{list(prime_generator(10))}")print(f"小于 50 的素数:{list(takewhile(lambdax:x<50,prime_infinite()))}")print("\n=== 考拉兹序列 ===")print(f"start=27:{list(collatz(27))}")print(f"start=6:{list(collatz(6))}")print("\n=== 内存对比 ===")n=1000fib_list=list(fibonacci(n))fib_gen=fibonacci(n)print(f"列表内存:{sys.getsizeof(fib_list):,}bytes")print(f"生成器内存:{sys.getsizeof(fib_gen)}bytes")print(f"内存比:{sys.getsizeof(fib_list)/sys.getsizeof(fib_gen):.0f}x"
http://www.cnnetsun.cn/news/2795304.html

相关文章:

  • 告别默认彩虹色!LabelMe 5.0.1保姆级教程:自定义图像分割标注颜色(附Python代码)
  • 一站式高效开源游戏编辑器:Harepacker-resurrected技术解析与实战指南
  • DxWrapper:让经典游戏在Windows 10/11上重获新生的兼容层解决方案
  • GHelper深度评测:华硕笔记本性能释放终极神器,告别Armoury Crate的臃肿束缚
  • Linux串口通信8字节限制解析:VMIN/VTIME参数与TTY缓冲区机制
  • SYNAPSE记忆架构:LLM智能体的长期记忆革新
  • 情感语音合成技术:原理、实现与应用
  • MCprep:为Minecraft动画师打造的Blender工作流加速器
  • 高效掌握数字电路设计的实用教程:从入门到精通
  • 1D到2D流体场构建:原理、实现与优化策略
  • CSDN AI分发数据流向揭秘:你的文章阅读量到底被谁看见、何时入库、能否导出?
  • 全国颜料厂主要集中在哪里?产区分布有什么规律?
  • HarmonyOS ArkUI Scroll 组件完全指南
  • 工程师视角:如何系统拆解消费电子产品的技术内核与真实价值
  • Vidupe视频内容去重:基于感知哈希与结构相似性的智能识别技术
  • 告别迷茫!用ESP32和LwIP理解TCP/IP:一个嵌入式工程师的网络协议栈入门笔记
  • 从星座图到硬件实现:手把手仿真QPSK家族(MATLAB/Python代码附后)
  • 实测ACS712ELC-05B电流传感器:5A模块真能测10A?手把手教你极限测试与校准
  • 别再傻傻分不清了!晶振、PLL、VCO到底怎么选?一个电路设计老鸟的避坑指南
  • 实战避坑:在XC7A35T上调试MicroBlaze LWIP时遇到的DMA卡死问题分析与解决思路
  • 430MHz八木天线DIY全攻略:从原理到实测优化
  • 红外遥控器开发实战:从MCU选型到低功耗设计的避坑指南
  • 大型组织AI自动化落地:从Excel宏到可审计流水线的实战路径
  • CMake编译报错‘is not able to compile a simple test program’?别慌,手把手教你排查Ubuntu上的编译器与glibc版本问题
  • machine 轴长注油孔
  • 华为展厅的数字展示怎么做?顶级科技企业的品牌空间如何用三维动画讲故事
  • 如何用Red Hat YAML插件实现专业级配置管理
  • 你的JAR包为啥双击打不开?IntelliJ IDEA导出可执行JAR的5个常见坑与排查指南
  • 从蚂蚁觅食到路径规划:蚁群算法(ACO)在Python中的实战应用与避坑指南
  • JewelCraft终极指南:如何在Blender中实现专业珠宝设计