python高级(1): 迭代器详解

文章目录

    • 1. 迭代器与可迭代对象(Iterable)
      • 1.1 可迭代对象(Iterable)
      • 1.2 迭代器( Iterator)
    • 2. 自定义一个可迭代器
      • 2.1 实现迭代器
      • 2.2 for 遍历迭代器的过程
    • 3. yolov8 Dataset实现案例

Python迭代器的作用是提供一种遍历数据集合的方式。它是一个可以被迭代的对象,可以使用迭代器的方法来逐个访问集合中的元素,而不需要事先知道集合的大小。

在深度学习的DatasetDataloader中,就是通过迭代器实现的,因此迭代器是一个非常重要的概念和工具

迭代器具有以下几个重要的特点:

  • 节省内存:迭代器一次只返回一个元素,不需要一次性将整个集合加载到内存中,这样可以节省内存空间,特别是在处理大型数据集合时非常有用。
  • 惰性计算:迭代器在需要时才会计算下一个元素,而不是一次性计算所有的元素。这种惰性计算的方式可以在处理大量数据时提高效率。
  • 可逆迭代:迭代器可以反向遍历集合,而不需要额外的复制和存储。
  • 支持并行处理:迭代器可以同时遍历多个集合,实现并行处理。

总之,迭代器提供了一种灵活、高效和节省内存的方式来遍历数据集合,是Python中非常重要的概念和工具。

1. 迭代器与可迭代对象(Iterable)

1.1 可迭代对象(Iterable)

表示该对象可迭代, 它的类中需要定义__iter__方法,只要是实现了__iter__方法的类就是可迭代对象

from collections.abc import Iterable, Iteratorclass A(object):def __init__(self):self.a = [1, 2, 3]def __iter__(self):# 此处返回啥无所谓return self.acls_a = A()
#  True
print(isinstance(cls_a, Iterable))
  • 可迭代对象,必须具备__iter__这个特殊函数,并且返回一个可迭代对象。可以通过isinstance(cls_a, Iterable)可以判断是否是可迭代对象

  • 如果一个Iterable,仅仅定义了__iter__方法,是没有特别大的用途,因为依然无法迭代,实际上 Iterable 仅仅是提供了一种抽象规范接口

1.2 迭代器( Iterator)

  • 迭代器Iterator一定是可迭代对象Iterable,但反过来,可迭代对象不一定是迭代器,因为迭代器只是可迭代对象的一种表示形式。
  • 实现了__next____iter__方法的类才能称为迭代器 就可以被 for 循环遍历数据。

因此,通过自定义实现迭代器Iterator,必须具备__next____iter__ 两个方法,如下案例所示:

class A(object):def __init__(self):self.index = -1self.a = [1, 2, 3]# 必须要返回一个实现了 __next__ 方法的对象,否则后面无法 for 遍历# 因为本类自身实现了 __next__,所以通常都是返回 self 对象即可def __iter__(self):return selfdef __next__(self):self.index += 1if self.index < len(self.a):return self.a[self.index]else:# 抛异常,for 内部会自动捕获,表示迭代完成raise StopIteration("遍历完了")cls_a = A()
print(isinstance(cls_a, Iterable)) # True 
print(isinstance(cls_a, Iterator)) # True  从这里可以看出来同时具有__iter__和__next__的类,是Iterator
print(isinstance(iter(cls_a), Iterator)) # True 这里加不加iter()都一样,因为这个类里面的iter也是直接返回自身(self)#另外补充一点这个a和上面类里面的a是不一样的;这里的用i(任意字母都可以)也能
for a in cls_a:print(a)
# 打印 1 2 3

-可以看到,通过实现__iter__, 和__next__这两个特殊方法,实现了迭代器A。

2. 自定义一个可迭代器

2.1 实现迭代器

在Python中从头开始构建迭代器很容易。我们只需要实现这些方法__iter__()__next__()

  • __iter__()方法需要返回迭代器对象, 最简单直接返回self,也可以返回新的可迭代对象。如果需要,可以执行一些初始化
  • __next__()方法必须返回序列中的下一项。在到达终点时,以及在随后的调用中,它必须引发StopIteration

这里,我们展示了一个示例,通过定义一个迭代器,手动实现python的range方法:

class Range:def __init__(self,start,stop,step):self.start = start  self.stop = stop  self.step = step def __iter__(self):self.value = self.startreturn selfdef __next__(self):# 1. 每执行一次next,需要返回一个值  # 2. 如果没有下一个值了,需要通过StopIteration 反馈异常if self.value < self.stop:old_value = self.value   self.value = self.value +self.step  return old_valueelse:raise StopIteration()for i in Range(0,5,1):print(i)

输出结果
在这里插入图片描述

我们知道python 的range方法 有三个参数:start_value, stop_value和step,因此我们也定义这3个参数。

  • 首先定义类的__init__方法
  • 然后实现__iter__方法,并返回可迭代对象,这里返回了本身(slef)。其中在__iter__方法中,初始化了返回值self.value__iter__方法中,如果需要,可以执行一些初始化
  • 最后通过__next__方法,定义每一次迭代输出的值。当迭代完了,没有下一个值,通过raise StopIteration(), 反馈错误。

在for循环中,最后反馈的raise StopIteration() erro,会被for循环处理掉,因此我们看不到报错的提醒。

2.2 for 遍历迭代器的过程

在这里插入图片描述
通过单步调试,可以观察到如下执行顺序:

  • (1) 首先调用__init__方法,对成员变量进行初始化
  • (2) 紧接着,进入__iter__,获得一个迭代器对象self
  • (3) 最后进入__next__方法,执行循环迭代过程,每迭代一次返回相应的迭代结果。最后迭代会执行raise StopIteration()语句,此时程序结束(异常被for处理,所以没有显示出来)

可以看到所谓for循环,本质上是就是一次次的执行__next__方法的过程。for循环可等价如下代码:

r = Range(0,5,1)	  # __init__ 构造对象
iteration = iter(r)   # 执行__iter__,获得迭代器对象
#iteration =  r.__iter__()next(iteration)      # 执行__next__
#iteration.__next__()
next(iteration)		 # 执行__next__
next(iteration)      # 执行__next__
next(iteration)      # 执行__next__
next(iteration)      # 执行__next__
try:next(iteration)
except StopIteration as e:pass
  • 最后一次会报StopIteration 异常,因此通过try except进行处理。
  • 注:`
    • iter(r) 就是 r.__iter__()实现的
    • next(iteration)就是通过iteration.__next__()实现的

3. yolov8 Dataset实现案例

class LoadImages:# YOLOv5 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4`def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1):"""Initialize instance variables and check for valid input."""if isinstance(path, str) and Path(path).suffix == '.txt':  # *.txt file with img/vid/dir on each linepath = Path(path).read_text().rsplit()files = []for p in sorted(path) if isinstance(path, (list, tuple)) else [path]:p = str(Path(p).resolve())if '*' in p:files.extend(sorted(glob.glob(p, recursive=True)))  # globelif os.path.isdir(p):files.extend(sorted(glob.glob(os.path.join(p, '*.*'))))  # direlif os.path.isfile(p):files.append(p)  # fileselse:raise FileNotFoundError(f'{p} does not exist')images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS]videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS]ni, nv = len(images), len(videos)self.img_size = img_sizeself.stride = strideself.files = images + videosself.nf = ni + nv  # number of filesself.video_flag = [False] * ni + [True] * nvself.mode = 'image'self.auto = autoself.transforms = transforms  # optionalself.vid_stride = vid_stride  # video frame-rate strideif any(videos):self._new_video(videos[0])  # new videoelse:self.cap = Noneassert self.nf > 0, f'No images or videos found in {p}. ' \f'Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}'def __iter__(self):"""Returns an iterator object for iterating over images or videos found in a directory."""self.count = 0return selfdef __next__(self):"""Iterator's next item, performs transformation on image and returns path, transformed image, original image, capture and size."""if self.count == self.nf:raise StopIterationpath = self.files[self.count]if self.video_flag[self.count]:# Read videoself.mode = 'video'for _ in range(self.vid_stride):self.cap.grab()ret_val, im0 = self.cap.retrieve()while not ret_val:self.count += 1self.cap.release()if self.count == self.nf:  # last videoraise StopIterationpath = self.files[self.count]self._new_video(path)ret_val, im0 = self.cap.read()self.frame += 1# im0 = self._cv2_rotate(im0)  # for use if cv2 autorotation is Falses = f'video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: 'else:# Read imageself.count += 1im0 = cv2.imread(path)  # BGRassert im0 is not None, f'Image Not Found {path}'s = f'image {self.count}/{self.nf} {path}: 'if self.transforms:im = self.transforms(im0)  # transformselse:im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0]  # padded resizeim = im.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGBim = np.ascontiguousarray(im)  # contiguousreturn path, im, im0, self.cap, s
  dataset = LoadImages(source, imgsz=imgsz, vid_stride=vid_stride)dataloader = build_dataloader(dataset, batch_size, workers, shuffle, rank)
  • 可以看到Dataset,也是通过一个迭代器实现,这样做的好处就是:需要时才会返回处理好的数据,而不需要一次性将整个集合加载到内存中,这样可以节省内存空间,也提高了数据处理的效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/243323.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【差分数组】【图论】【分类讨论】【整除以2】100213按距离统计房屋对数目

作者推荐 【动态规划】【数学】【C算法】18赛车 本文涉及知识点 差分数组 图论 分类讨论 整除以2 LeetCode100213按距离统计房屋对数目 给你三个 正整数 n 、x 和 y 。 在城市中&#xff0c;存在编号从 1 到 n 的房屋&#xff0c;由 n 条街道相连。对所有 1 < i < n…

ARM_Linux中GCC编译器的使用

目录 前言: GCC编译过程: 预处理&#xff1a; 编译阶段&#xff1a; 汇编&#xff1a; 链接阶段 GCC的常见使用 前言: 什么是GCC: gcc的全称是GNU Compiler Collection&#xff0c;它是一个能够编译多种语言的编译器。最开始gcc是作为C语言的编译器&#xff08;GNU C Co…

深度学习记录--指数加权平均

指数加权移动平均(exponentially weighted moving averages) 如何对杂乱的数据进行拟合&#xff1f; 通过指数加权平均可以把数据图近似拟合成一条曲线 公式&#xff1a; 其中表示第t个平均数&#xff0c;表示第t-1个平均数&#xff0c;表示第t个数据&#xff0c;表示变化参数…

tkinter绘制组件(40)——滚动选值框

tkinter绘制组件&#xff08;40&#xff09;——滚动选值框 引言布局函数结构文本展示选择器布局完整函数代码 效果测试代码最终效果 github项目pip下载结语 引言 2023年基本没有怎么更新TinUI组件部分&#xff0c;而滚动选值框&#xff08;picker&#xff09;&#xff0c;是在…

《WebKit 技术内幕》学习之七(4): 渲染基础

4 WebKit软件渲染技术 4.1 软件渲染过程 在很多情况下&#xff0c;也就是没有那些需要硬件加速内容的时候&#xff08;包括但不限于CSS3 3D变形、CSS3 03D变换、WebGL和视频&#xff09;&#xff0c;WebKit可以使用软件渲染技术来完成页面的绘制工作&#xff08;除非读者强行…

Vue基础入门 - Vue的快速创建、Vue的开发者工具安装及Vue的常用指令(v-model,v-bind,computed计算属性,watch侦听器)

Vue 文章目录 Vue1 什么是Vue2 创建Vue实例2.1 快速创建2.2 插值表达式 {{}}2.3 响应式特性2.3.1 访问与修改 3 Vue开发者工具安装4 Vue中的常用指令4.1 内容渲染指令4.2 条件渲染指令4.3 事件绑定指令4.4 属性绑定指令4.5 案例-上下页图片翻页4.6 列表渲染指令4.7 案例-能删除…

flink部署模式介绍

在一些应用场景中&#xff0c;对于集群资源分配和占用的方式&#xff0c;可能会有特定的需求。Flink 为各种场景提供了不同的部署模式&#xff0c;主要有以下三种&#xff0c;它们的区别主要在于&#xff1a; 集群的生命周期以及资源的分配方式&#xff1b;应用的 main 方法到…

谷歌浏览器通过network模拟HTTP中的GET/POST请求获取response

1、F12打开network选中需要模拟的方法Copy->Copy as fetch 2、通过AI帮你进行转换一下调用格式 原代码 fetch("https://mp.amap.com/api/forward/aggregate?mtop.alsc.kbt.intergration.toolkit.call.queryCallBlockInfo", {"headers": {"acce…

03--数据库连接池

1、数据库连接池 1.1 JDBC数据库连接池的必要性 在使用开发基于数据库的web程序时&#xff0c;传统的模式基本是按以下步骤&#xff1a; 在主程序&#xff08;如servlet、beans&#xff09;中建立数据库连接进行sql操作断开数据库连接 这种模式开发&#xff0c;存在的问题:…

PyTorch 中的距离函数深度解析:掌握向量间的距离和相似度计算

目录 Pytorch中Distance functions详解 pairwise_distance 用途 用法 参数 数学理论公式 示例代码 cosine_similarity 用途 用法 参数 数学理论 示例代码 输出结果 pdist 用途 用法 参数 数学理论 示例代码 总结 Pytorch中Distance functions详解 pair…

Git学习笔记(第1章):Git概述

目录 1.1 版本控制 1.1.1 何为版本控制 1.1.2 为什么需要版本控制 1.1.3 版本控制工具 1.2 发展历史 1.3 工作机制 1.4 代码托管中心&#xff08;远程库&#xff09; Git是一个免费的、开源的分布式版本控制系统&#xff0c;可以快速高效地处理从小型到大型的各种项目。…

【UEFI基础】EDK网络框架(UDP4)

UDP4 UDP4协议说明 UDP的全称是User Datagram Protocol&#xff0c;它不提供复杂的控制机制&#xff0c;仅利用IP提供面向无连接的通信服务。它将上层应用程序发来的数据在收到的那一刻&#xff0c;立即按照原样发送到网络。 UDP报文格式&#xff1a; 各个参数说明如下&…

AD导出BOM表 导出PDF

1.Simple BOM: 这种模式下&#xff0c;最好在pcb界面&#xff0c;这样的导出的文件名字是工程名字&#xff0c;要是在原理图界面导出&#xff0c;会以原理图的名字命名表格。 直接在菜单栏 报告->Simple BOM 即可导出物料清单&#xff0c;默认导出 comment pattern qu…

【Java】学习一门开发语言,从TA的Hello World开始

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《Java》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握…

【Redis】非关系型数据库之Redis的主从复制、哨兵和集群高可用

目录 一、主从复制、哨兵、集群的区别 二、主从复制 2.1主从复制的作用 2.2主从复制的原理 2.3主从复制的实操 步骤一&#xff1a;环境准备 步骤二&#xff1a;安装Redis以及配置文件修改 Redis的主从配置文件都一样 步骤四&#xff1a;验证主从复制 三、哨兵 3.1哨兵…

NODE介绍和环境安装

浏览器是JS的前端运行环境 Node.js是JS的后端运行环境 Node.js中无法调用DOM和BOM等浏览器内置API 基于Express框架&#xff0c;快速构建web应用 基于Electron框架&#xff0c;构建跨平台桌面应用 基于restify框架快速构建API接口项目 读写数据库 下载Node.js环境 网址&…

【分布式技术】注册中心zookeeper

目录 一、ZooKeeper是什么 二、ZooKeeper的工作机制 三、ZooKeeper特点 四、ZooKeeper数据结构 五、ZooKeeper应用场景 ●统一命名服务 ●统一配置管理 ●统一集群管理 ●服务器动态上下线 ●软负载均衡 六、ZooKeeper的选举机制 七、实操部署ZooKeeper集群 步骤一…

线性代数:矩阵运算(加减、数乘、乘法、幂、除、转置)

目录 加减 数乘 矩阵与矩阵相乘 矩阵的幂 矩阵转置 方阵的行列式 方阵的行列式&#xff0c;证明&#xff1a;|AB| |A| |B| 加减 数乘 矩阵与矩阵相乘 矩阵的幂 矩阵转置 方阵的行列式 方阵的行列式&#xff0c;证明&#xff1a;|AB| |A| |B|

续签KES证书

MiniO KES&#xff08;密钥加密服务&#xff09;是 MinIO 开发的一项服务&#xff0c;旨在弥合在 Kubernetes 中运行的应用程序与集中式密钥管理服务 &#xff08;KMS&#xff09; 之间的差距。中央 KMS 服务器包含所有状态信息&#xff0c;而 KES 在需要执行与获取新密钥或更新…

Unity 工厂方法模式(实例详解)

文章目录 在Unity中&#xff0c;工厂方法模式是一种创建对象的常用设计模式&#xff0c;它提供了一个接口用于创建对象&#xff0c;而具体的产品类是由子类决定的。这样可以将对象的创建过程与使用过程解耦&#xff0c;使得代码更加灵活和可扩展。 工厂模式的主要优点如下&…