Python 迭代器与生成器专项练习:6 道编程题从入门到精通
配套专栏:Python 全栈修炼之路 第 13 篇《迭代器与生成器——惰性求值的艺术》难度分布:⭐ → ⭐⭐ → ⭐⭐ → ⭐⭐⭐ → ⭐⭐⭐ → ⭐⭐⭐⭐核心覆盖:__iter__/__next__、yield、生成器表达式、itertools、yield 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。CountDown:内部维护一个计数器self.current,每次__next__返回当前值并递减,到 0 时抛出StopIteration。Stepper:支持start、stop、step三个参数,类似range()但作为类实现。需要处理正步长和负步长两种情况。一次性特性:迭代器耗尽后再次遍历返回空列表,这是迭代器与可迭代对象的核心区别。🖥️ 参考代码fromcollections.abcimportIteratorclassCountDown:"""倒计时迭代器:从 start 倒数到 1。"""def__init__(self,start:int):ifstart0: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.step0andself.currentself.stop:self._exhausted=TrueraiseStopIterationifself.step0andself.currentself.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:x50,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 截取:有限斐波那契:yield每次产生一个数,用count控制数量。无限斐波那契:while True+yield,永不停止,配合islice截取。素数生成器:维护一个素数列表,用试除法判断新数是否为素数。内存优势:生成器不存储所有值,只在需要时计算,适合大数据量。🖥️ 参考代码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*pcandidate:breakifcandidate%p==0:is_prime=Falsebreakifis_prime:primes.append(candidate)yieldcandidate candidate+=1defprime_infinite():"""无限素数生成器。"""primes=[]candidate=2whileTrue:is_prime=Trueforpinprimes:ifp*pcandidate: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:x50,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"