Python迭代器深入解析与实战

发布时间:2026/6/30 1:06:34

Python迭代器深入解析与实战 Python 迭代器详细学习笔记一、什么是迭代器迭代器可以理解为一种可以一个一个取出数据的对象。比如列表中有多个元素nums[10,20,30]我们可以使用for循环一个一个取出nums[10,20,30]fornuminnums:print(num)输出结果102030这里的核心思想就是每次只取一个数据直到没有数据为止。迭代器就是专门用来实现这种“逐个取值”效果的对象。二、可迭代对象和迭代器的区别1. 什么是可迭代对象可迭代对象是指可以被for循环遍历的对象。常见的可迭代对象有list_data[1,2,3]# 列表tuple_data(1,2,3)# 元组str_dataabc# 字符串dict_data{name:Tom}# 字典set_data{1,2,3}# 集合range_datarange(5)# range 对象这些对象都可以使用for循环names[张三,李四,王五]fornameinnames:print(name)输出结果张三 李四 王五2. 什么是迭代器迭代器不仅可以被for循环遍历还可以使用next()函数手动取值。nums[10,20,30]# 使用 iter() 把列表转换成迭代器iteratoriter(nums)print(next(iterator))# 取出第 1 个元素print(next(iterator))# 取出第 2 个元素print(next(iterator))# 取出第 3 个元素输出结果1020303. 可迭代对象和迭代器的核心区别对象能否使用 for 循环能否直接使用 next()可迭代对象可以不一定迭代器可以可以例如列表是可迭代对象但列表本身不是迭代器nums[1,2,3]print(next(nums))运行后会报错TypeError:listobjectisnotan iterator正确写法nums[1,2,3]# 先使用 iter() 获取迭代器iteratoriter(nums)print(next(iterator))输出结果1三、iter()和next()的用法1.iter()的作用iter()用来获取一个对象的迭代器。nums[100,200,300]# 将列表转换成迭代器iteratoriter(nums)print(iterator)此时iterator就是一个迭代器对象。2.next()的作用next()用来从迭代器中取出下一个元素。nums[100,200,300]iteratoriter(nums)print(next(iterator))# 100print(next(iterator))# 200print(next(iterator))# 300每调用一次next()迭代器就向后移动一步。3. 数据取完后会怎样nums[100,200,300]iteratoriter(nums)print(next(iterator))# 100print(next(iterator))# 200print(next(iterator))# 300# 已经没有元素了再取会报错print(next(iterator))运行后会报错StopIterationStopIteration表示迭代器里面已经没有数据了。四、迭代器的工作原理迭代器内部可以理解为有一个“指针”用来记录当前取到哪里了。以列表[10, 20, 30]为例nums[10,20,30]iteratoriter(nums)print(next(iterator))# 第一次取得到 10print(next(iterator))# 第二次取得到 20print(next(iterator))# 第三次取得到 30执行过程可以理解为初始位置还没有开始取值 第一次 next() - 取出 10 第二次 next() - 取出 20 第三次 next() - 取出 30 第四次 next() - 没有数据抛出 StopIteration迭代器不会一次性把所有数据都取出来而是用一次取一次。这也叫做惰性取值。惰性取值的意思是需要的时候才取不需要的时候不取。五、StopIteration异常的作用StopIteration是迭代器结束时抛出的异常。它的作用是告诉程序数据已经取完了不要再继续取了。示例nums[1,2]iteratoriter(nums)print(next(iterator))# 1print(next(iterator))# 2print(next(iterator))# 没有数据了抛出 StopIteration如果不想让程序直接报错可以使用try...except捕获异常nums[1,2]iteratoriter(nums)try:print(next(iterator))print(next(iterator))print(next(iterator))exceptStopIteration:print(数据已经取完了)输出结果12数据已经取完了不过在日常开发中我们很少手动捕获StopIteration因为for循环会自动处理它。六、如何自定义迭代器类如果想让一个对象成为迭代器需要实现两个方法__iter__()__next__()下面自定义一个迭代器实现从 1 数到 5。classMyIterator:def__init__(self):# 当前数字从 1 开始self.current1def__iter__(self):# 迭代器对象的 __iter__() 通常返回自己returnselfdef__next__(self):# 如果当前数字小于等于 5就继续返回ifself.current5:numself.current# 每取一次下次就往后移动self.current1returnnumelse:# 没有数据时必须抛出 StopIterationraiseStopIteration iteratorMyIterator()print(next(iterator))# 1print(next(iterator))# 2print(next(iterator))# 3print(next(iterator))# 4print(next(iterator))# 5也可以使用for循环遍历iteratorMyIterator()fornuminiterator:print(num)输出结果12345七、__iter__()和__next__()方法详解1.__iter__()方法__iter__()方法的作用是返回一个迭代器对象。对于迭代器自身来说通常返回self。def__iter__(self):returnself意思是我自己就是迭代器所以返回我自己。2.__next__()方法__next__()方法的作用是返回下一个元素。def__next__(self):# 返回下一个值returnvalue如果已经没有元素了就需要抛出raiseStopIteration3. 完整示例倒计时迭代器classCountDown:def__init__(self,start):# 从传入的数字开始倒计时self.currentstartdef__iter__(self):# 返回迭代器本身returnselfdef__next__(self):# 如果当前数字大于 0继续返回ifself.current0:numself.current self.current-1returnnumelse:# 倒计时结束raiseStopIteration count_downCountDown(5)fornumincount_down:print(num)输出结果54321八、迭代器与for循环的关系平时我们写nums[10,20,30]fornuminnums:print(num)实际上Python 内部大致做了这些事情nums[10,20,30]# 第一步先调用 iter() 获取迭代器iteratoriter(nums)# 第二步不断调用 next()whileTrue:try:numnext(iterator)print(num)exceptStopIteration:# 如果取完了就结束循环break所以for循环的本质就是1. 调用 iter() 获取迭代器 2. 不断调用 next() 取值 3. 遇到 StopIteration 后结束循环这也是为什么只要一个对象实现了__iter__()和__next__()它就可以被for循环遍历。九、迭代器和生成器的区别生成器可以理解为一种更简单的迭代器写法。1. 普通迭代器写法classMyIterator:def__init__(self):self.current1def__iter__(self):returnselfdef__next__(self):ifself.current3:numself.current self.current1returnnumelse:raiseStopIteration iteratorMyIterator()fornuminiterator:print(num)输出结果1232. 生成器写法使用yield可以创建生成器。defmy_generator():yield1yield2yield3genmy_generator()fornumingen:print(num)输出结果123可以看到生成器写法更简单。3.yield是什么yield和return有点像都会返回值。但是它们有明显区别对比项returnyield作用返回结果并结束函数返回一个值但函数暂停是否能继续执行不能继续执行可以继续执行常用于普通函数生成器函数示例deftest():print(开始)yield1print(继续)yield2print(结束)yield3gentest()print(next(gen))print(next(gen))print(next(gen))输出结果开始1继续2结束3执行过程是第一次 next()运行到 yield 1暂停 第二次 next()从 yield 1 后面继续运行遇到 yield 2暂停 第三次 next()从 yield 2 后面继续运行遇到 yield 3暂停4. 迭代器和生成器对比总结对比项迭代器生成器实现方式需要写类实现__iter__()和__next__()使用函数和yield写法复杂度稍微复杂更简单是否也是迭代器是是使用场景适合复杂迭代逻辑适合简单按需生成数据生成器本质上也是迭代器。可以验证defgen_func():yield1yield2gengen_func()print(iter(gen)isgen)# True说明生成器本身就是迭代器print(next(gen))# 1print(next(gen))# 2十、常见使用场景和注意事项1. 遍历容器数据列表、元组、字符串、字典都可以迭代。names[张三,李四,王五]fornameinnames:print(name)输出结果张三 李四 王五2. 读取大文件如果文件特别大不建议一次性读取全部内容。不推荐写法# 一次性读取所有内容文件很大时会占用大量内存withopen(data.txt,r,encodingutf-8)asf:contentf.read()推荐写法# 一行一行读取节省内存withopen(data.txt,r,encodingutf-8)asf:forlineinf:print(line.strip())文件对象本身就是可迭代对象。3. 惰性计算节省内存比如生成 1 到 100000000 的数字。使用列表会一次性创建所有数据nums[iforiinrange(100000000)]这会占用大量内存。使用生成器则是需要时才生成nums(iforiinrange(100000000))print(next(nums))# 0print(next(nums))# 1print(next(nums))# 2这种方式更加节省内存。4. 迭代器只能往前走迭代器取过的数据一般不能回头再取。nums[1,2,3]iteratoriter(nums)print(next(iterator))# 1print(next(iterator))# 2# 继续取只能取到 3不能再回到 1print(next(iterator))# 35. 迭代器通常只能遍历一次nums[1,2,3]iteratoriter(nums)fornuminiterator:print(num)print(第二次遍历)fornuminiterator:print(num)输出结果123第二次遍历第二次没有输出因为迭代器已经被取完了。如果还想重新遍历需要重新创建迭代器nums[1,2,3]iterator1iter(nums)iterator2iter(nums)fornuminiterator1:print(num)print(重新遍历)fornuminiterator2:print(num)输出结果123重新遍历1236. 不要在普通列表上直接使用next()错误写法nums[1,2,3]print(next(nums))运行后会报错TypeError:listobjectisnotan iterator正确写法nums[1,2,3]iteratoriter(nums)print(next(iterator))7. 字典迭代默认遍历 keyuser{name:Tom,age:18}forkeyinuser:print(key)输出结果name age如果想遍历键值对可以使用items()user{name:Tom,age:18}forkey,valueinuser.items():print(key,value)输出结果name Tom age18十一、重点总结1. 迭代器是什么迭代器就是可以使用next()一个一个取值的对象。nums[1,2,3]iteratoriter(nums)print(next(iterator))# 12. 可迭代对象和迭代器的区别可迭代对象可以被for循环遍历。迭代器可以被next()手动取值。nums[1,2,3]# nums 是可迭代对象iteratoriter(nums)# iterator 是迭代器print(next(iterator))3.iter()和next()iteratoriter([1,2,3])print(next(iterator))# 1print(next(iterator))# 2print(next(iterator))# 3iter()获取迭代器。next()获取下一个元素。4.StopIteration当迭代器没有数据时会抛出StopIteration。iteratoriter([1])print(next(iterator))# 1print(next(iterator))# StopIterationStopIteration的作用是告诉程序数据已经取完了。5. 自定义迭代器自定义迭代器必须实现__iter__()__next__()简单结构classMyIterator:def__iter__(self):returnselfdef__next__(self):pass6.for循环的本质for循环底层大致等价于iteratoriter(可迭代对象)whileTrue:try:valuenext(iterator)exceptStopIteration:break7. 生成器生成器是更简单的迭代器写法。defmy_gen():yield1yield2yield3只要函数中出现yield这个函数调用后返回的就是生成器对象。十二、练习题练习 1手动使用iter()和next()有如下列表nums[10,20,30,40]要求使用iter()获取迭代器使用next()依次取出所有元素尝试多调用一次next()观察会发生什么。练习 2自定义一个迭代器请自定义一个迭代器类EvenNumber实现输出 2 到 10 之间的偶数。期望效果evenEvenNumber()fornumineven:print(num)输出结果246810提示代码classEvenNumber:def__init__(self):self.current2def__iter__(self):returnselfdef__next__(self):pass练习 3用生成器改写迭代器请使用生成器函数实现输出 1 到 5。期望效果defmy_generator():passfornuminmy_generator():print(num)输出结果12345提示yield十三、推荐记忆口诀可迭代对象能被 for 循环遍历。 迭代器能被 next() 一个一个取值。 iter()把可迭代对象变成迭代器。 next()从迭代器中取下一个值。 StopIteration告诉程序数据取完了。 生成器用 yield 写出来的简化版迭代器。

相关新闻