Python迭代器iter及生成器介绍

Python迭代器iter及生成器介绍本文介绍了 Python 中迭代器的基础概念 如列表 字典 文件和生成器的迭代 展示了迭代器与列表的区别 并通过实例说明了 next 函数的用法

大家好,欢迎来到IT知识分享网。

简介

Python中常见的迭代器有:

  1. 列表迭代器:使用for循环遍历列表。
  2. 字典迭代器:使用for循环遍历字典的键、值或键值对。
  3. 文件迭代器:使用for循环遍历文件中的行。
  4. 生成器:使用yield语句来生成迭代器,可以节省内存空间和计算资源。
  5. itertools模块中的迭代器:包括countcyclerepeatchainzip_longestislicetakewhiledropwhile等。这些迭代器可以实现更加复杂的迭代操作。

先看几个实例

实例

>>> lst = [1, 2, 3] >>> for i in iter(lst): ... print(i) Out[0]: 1 2 3 >>> b = iter(lst) # 迭代器和列表的区别:经历一次for in之后,再次for in的话,再次遍历则返回空。 >>> for i in b: ... print(i) Out[1]: 1 2 3 

迭代器和列表的区别:经历一次for in之后,再次for in的话,再次遍历则返回

>>> for i in b: ... print(i) Out[2]: 
>>> type(b) Out[3]: list_iterator 
  • 列表和迭代器区别
    • 列表不论遍历多少次,表头位置始终是第一个元素;
    • 迭代器遍历结束后,不再指向原来的表头位置,而是为最后元素的下一个位置
fns = { 
   '10min': 139, '20min': 159} next(iter(fns.keys())) Out[7]: '10min' next(iter(fns.values())) Out[8]: 139 

在Python中,next不是关键字,而是一个内建函数。这个函数用于从迭代器中获取下一个项目。

test = [2, 3] iter_test = iter(test) next(iter_test) Out[9]: 2 next(iter_test) Out[10]: 3 next(iter_test) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration 
d = { 
   'one': 1, 'two': 2, 'three': 3} d Out[11]: { 
   'three': 3, 'two': 2, 'one': 1} iterd = iter(d) # 字典的迭代器会默认遍历字典的键(key) next(iterd) Out[12] 'three' next(iterd) Out[13]'two' next(iterd) Out[14]'one' >>> next(iterd) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration 
  • 遍历列表,表头位置始终不变;
  • 遍历迭代器,表头位置相应改变;
  • next 函数执行一次,迭代对象指向就前进一次;
  • StopIteration 触发时,意味着已到迭代器尾部;

描述

所谓的iterator对象,就是有个next()方法的对象。next方法的惯例或约定(convention)是,每执行一次就返回下一个值(因此它要自己记录状态,通常是在iterator对象上记录),直到没有值的时候raiseStopIteration。

传1个参数:参数collection应是一个容器,支持迭代协议(即定义有__iter__()函数),或者支持序列访问协议(即定义有__getitem__()函数),否则会返回TypeError异常。

传2个参数:当第二个参数sentinel出现时,参数callable应是一个可调用对象(实例),即定义了__call__()方法,当枚举到的值等于哨兵时,就会抛出异常StopIteration。

语法

iter(object[, sentinel])

参数

  • object – 支持迭代的集合对象。
  • sentinel – 如果传递了第二个参数,则参数 object 必须是一个可调用的对象(如,函数),此时,iter 创建了一个迭代器对象,每次调用这个迭代器对象的__next__()方法时,都会调用 object。

返回值

迭代器对象

弄清楚几个概念

  • 可迭代对象iterable:python 中常见的可迭代对象:list、tuple、dict、set、str等。
  • 迭代iterator:
    • Python 的 Iterator 对象表示的是一个数据流,Iterator 对象可以被 next() 函数调用并不断返回下一个数据,直到没有数据时抛出 StopIteration 错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过 next() 函数实现按需计算下一个数据,所以 Iterator 的计算是惰性的,只有在需要返回下一个数据时它才会计算。
    • Iterator 甚至可以表示一个无限大的数据流,例如全体自然数。而使用 list 是永远不可能存储全体自然数的。
    • 所以可迭代对象不是迭代器。
  • 迭代iter
    • 将可迭代对象变为迭代器的动作。

迭代

  • 如何迭代
    python 使用内置函数iter 进行迭代
''' iter语法为: iter(object[, sentinel]),有两种方式使用 第一种如下 ''' list = range(6) It = iter(list) ''' 第二种,如果传递了第二个参数,则参数 object 必须是一个可调用的对象(如,函数),此时,iter 创建了一个迭代器对象,每次调用这个迭代器对象的__next__()方法时,都会调用 object,直至迭代到元素sentinel。 ''' from queue import Queue q = Queue()# 创建队列对象 for i in range(5): q.put(i)# 依次放入5个数字 q.put('END')# 放入结束标志 def test(): return q.get()# 取数据 for item in iter(test, 'END'):# 持续执行test()函数,直到返回’END’ print(item, end=' ') 
  • 如何判断对象为可迭代对象
''' 使用内置函数isinstance 判断,例如判断列表是否可迭代 ''' from collections import Iterable isinstance([], Iterable) Output: True 
  • 如何判断对象是否为迭代器
''' 使用内置函数isinstance 判断,例如判断列表是否可迭代 ''' from collections import Iterator isinstance([], Iterator) Output: False, 因为list还没有被转为迭代器,仅是可迭代对象 
  • 迭代器执行逻辑
    迭代器被创建后,就可以使用 next 方法进行迭代,直至迭代器所有的元素全部被调用,程序抛出StopIteration 报错。
  • 如何使用迭代器
''' 主要是next 方法的使用 ''' # 首先获得Iterator对象: it = iter([1, 2, 3, 4, 5]) # 循环: while True: try: # 获得下一个值: x = next(it) except StopIteration: # 遇到StopIteration就退出循环 break 

有趣应用

a = [1, 2, 3, 4, 5, 6] ...: b = zip(*([iter(a)] * 2)) ...: for i in b: ...: print(i) ...: (1, 2) (3, 4) (5, 6) list(zip([iter(a)])) Out[35]: [(<list_iterator at 0x198cfdaea00>,)] list(zip(*[iter(a)])) Out[36]: [(1,), (2,), (3,), (4,), (5,), (6,)] list(zip(*([iter(a)] * 2))) Out[37]: [(1, 2), (3, 4), (5, 6)] list(zip(*([iter(a)] * 3))) Out[38]: [(1, 2, 3), (4, 5, 6)] list([iter(a)]) Out[39]: [<list_iterator at 0x198cfdcc8e0>] for i in [iter(a)] * 2: print(i) <list_iterator object at 0x00000198CFD1C9A0> <list_iterator object at 0x00000198CFD1C9A0> 

next 应用介绍

区间表示应该使用圆括号 () 和方括号 [] 来表示开闭区间,且二者表示效果一致,均表示左右皆是闭区间。以下是已校正的代码:

import pandas as pd # 创建一个映射字典,根据total值映射到weight值 total_to_weight = { 
    (2.5, 4.5): 1.0, (4.5, 6.0): 1.2, (6.0, 8.5): 1.3, (8.5, 10.5): 1.2, (10.5, 12.5): 1.1, (12.5, 100): 1.0 } # 使用map函数将total映射到weight列,并提供默认值 turn_ws_percent['weight'] = turn_ws_percent.index.map( lambda x: next((weight for bins, weight in total_to_weight.items() if bins[0] <= x < bins[1]), None) ) 

现在,代码应该能够正确地将bin的值映射到相应的weight值上。

解读上面的代码:

这段代码是在处理一个名为 turn_ws_percent 的DataFrame,并根据索引的值来计算一个新的列 'weight' 的值。逐步解释:

  1. turn_ws_percent['weight']:这部分表示将一个名为 'weight' 的新列添加到 turn_ws_percent 中,用于存储计算的结果。
  2. .index.map(...):这是一个操作,它对 turn_ws_percent 的索引进行映射,并将映射结果存储在 'weight' 列中。
  3. lambda x: next((weight for bins, weight in total_to_weight.items() if bins[0] <= x < bins[1]), None):这是一个lambda函数,它接受一个参数 x,表示索引的值。这个 lambda 函数的作用是根据索引值 x 查找 total_to_weight 这个字典中的对应权重值。
    • total_to_weight 是一个字典,其中包含了区间(bins)和相应的权重值。这个lambda函数的作用是对 total_to_weight 中的每个区间进行遍历,找到第一个满足条件 bins[0] <= x < bins[1] 的区间,并返回该区间对应的权重值 weight
    • 如果没有找到满足条件的区间,就返回 None

总的来说,这段代码的目的是根据 turn_ws_percent DataFrame或Series 的索引值,在 total_to_weight 字典中查找相应的权重值,并将这些权重值存储在一个新的 'weight' 列中。这可以用于给索引值添加权重信息。如果没有找到相应的区间, 'weight' 列将包含 None

next 介绍
next() 是一个内置函数,通常用于从可迭代对象中获取下一个元素。在上述代码中,next() 被用于在字典 total_to_weight 中查找满足特定条件的元素。

具体地,next() 函数的用法如下:

next(iterator, default) 
  • iterator 是一个可迭代对象,通常是一个迭代器(例如,通过 iter() 函数创建的)。
  • default 是一个可选参数,表示当迭代器耗尽时,返回的默认值。

在上述代码中的 lambda 函数中,next() 的目的是从 total_to_weight.items() 这个可迭代对象中获取下一个元素,但带有一个条件,即元素必须满足 bins[0] <= x < bins[1]

具体来说:

  • total_to_weight.items() 返回了一个包含字典键值对的可迭代对象,每个键值对的格式是 (bins, weight),其中 bins 是区间,weight 是权重值。
  • next() 函数在可迭代对象中查找并返回满足条件的第一个元素,条件由 lambda 函数中的 bins[0] <= x < bins[1] 定义。
  • 如果找到满足条件的元素,则返回该元素的 weight 值。
  • 如果没有找到满足条件的元素,或者迭代器耗尽了(没有更多的元素可供查找),则返回 None,或者在 next() 函数的第二个参数中指定的默认值。

总之,next() 用于在可迭代对象中查找并返回符合条件的下一个元素,如果没有找到则返回默认值。在上述代码中,它用于查找满足区间条件的权重值。

生成器

原始代码

ans_file_paths = [path for path in file_paths if any(id_ in path for id_ in ids_set)] 

修改后代码

def file_generator(root_dir, ids_set): """生成器:用于生成符合条件的文件路径""" file_pattern = os.path.join(root_dir, '*csv') file_paths = glob(file_pattern) for path in file_paths: if any(id_ in path for id_ in ids_set): yield path 

原始代码解释:

  1. 列表推导式:这段代码使用了 Python 中的列表推导式(list comprehension),是一种简洁的方式来生成一个列表。
  2. 条件筛选:它从 file_paths 列表中筛选出符合条件的文件路径。具体来说,它会检查 ids_set 中的每个 id_ 是否出现在路径 path 中。
  3. 结果:最终,ans_file_paths 将包含所有符合条件的文件路径。

修改后解释:

  1. 定义了一个生成器函数:修改后的代码将原来的列表推导式转换成了一个生成器函数 file_generator。生成器是一种特殊的迭代器,允许你逐个生成值,而不是一次性生成所有值。
  2. 使用 yield 关键字:在 file_generator 函数中,使用了 yield 关键字。当函数执行到 yield 时,它会返回一个值并暂停执行,以后再调用时会从暂停的地方继续执行。这意味着生成器不会一次性将所有结果都计算出来,而是按需生成。
  3. 内存效率:使用生成器的一个主要好处是内存效率。原始代码会一次性创建一个包含所有符合条件路径的列表,这在处理大量文件路径时可能会消耗大量内存。而生成器则只会在需要时生成一个路径,这样可以节省内存。
  4. 可读性和可重用性:将代码封装在函数中提高了可读性和可重用性。你可以多次调用 file_generator,并在不同的地方使用它,而不必每次都写一遍筛选逻辑。

总结

  • 原始代码:使用列表推导式一次性生成所有符合条件的文件路径,可能会占用较多内存。
  • 修改后代码:使用生成器按需生成文件路径,节省内存,提高了代码的可读性和可重用性。

参考链接

[1] Python iter() 函数 2022.7
[2] python iter( )函数 2016.7
[3] Python-迭代器iter-使用 2018.3
[4] Python怎么取出列表中的相邻元素?2020.5
[5] Python 笔记(03)— 列表和迭代器区别 2022.6

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/148568.html

(0)
上一篇 2025-03-30 13:00
下一篇 2025-03-30 13:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信