数据结构与算法 学习笔记(2)- 迭代器与生成器

迭代器与生成器 迭代器(lterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署lterator接口,就可以完成遍历操作,ES6新增遍历方式for...of。原生具备lterator接口的数据有Array,Arguments,Set,Map,String,NodeList。... 阅读详情

P数据结构与算法 学习笔记(2)- 迭代器与生成器

本文转自:https://www.cnblogs.com/vipchenwei/p/6991204.html
最近学习时遇到了迭代器、生成器的理解,这篇文章介绍的十分清晰,于是就转来了。

本文讲述了以下几个方面:

1.何为迭代,何为可迭代对象,何为生成器,何为迭代器?

2.可迭代对象与迭代器之间的区别

3.生成器内部原理解析,for循环迭代内部原理解析

4.可迭代对象,迭代器,生成器,生成器函数之间关系

1.迭代

要搞清楚什么关于迭代器,生成器,可迭代对象,前提是我们要理解何为迭代。

第一,迭代需要重复进行某一操作

第二,本次迭代的要依赖上一次的结果继续往下做,如果中途有任何停顿,都不能算是迭代.

下面来看看几个例子,你就会更能理解迭代的含义。

# example1
# 非迭代
count = 0
while count < 10:
    print("hello world")
    count += 1
# example2
# 迭代
count = 0
while count < 10:
    print(count)
    count += 1

例子1,仅仅只是在重复一件事,那就是不停的打印"hello world",并且,这个打印的结果并不依赖上一次输出的值。而例子2,就很好地说明迭代的含义,重复+继续。

2.可迭代对象

按照上面迭代的含义,我们应该能够知道何为可迭代对象。顾名思义,就是一个对象能够被迭代的使用。那么我们该如何判断一个对象是否可迭代呢?

Python提供了模块collections,其中有一个isinstance(obj,string)的函数,可以判断一个对象是否为可迭代对象。看下面实例:

from collections import Iterable

f = open('a.txt')
i = 1
s = '1234'
d = {'abc':1}
t = (1,2,344)
m = {1,2,34,}

print(isinstance(i, Iterable))  # 判断整型是否为可迭代对象
print(isinstance(s, Iterable))  # 判断字符串对象是否为可迭代对象  
print(isinstance(d, Iterable))  # 判断字典对象是否为可迭代对象
print(isinstance(t, Iterable))  # 判断元组对象是否为可迭代对象
print(isinstance(m, Iterable))  # 判断集合对象是否为可迭代对象
print(isinstance(f, Iterable))  # 判断文件对象是否为可迭代对象


########输出结果#########

False
True
True
True
True
True

由上面得出,除了整型之外,python内的基本数据类型都是可迭代对象,包括文件对象。那么,python内部是如何知道一个对象是否为可迭代对象呢?答案是,在每一种数据类型对象中,都会有有一个__iter__()方法,正是因为这个方法,才使得这些基本数据类型变为可迭代。

如果不信,我们可以来看看下面代码片段:

f = open('a.txt')
i = 1
s = '1234'
d = {'abc':1}
t = (1,2,344)
m = {1,2,34,}


# hasattr(obj,string) 判断对象中是否存在string方法
print(hasattr(i, '__iter__'))
print(hasattr(s, '__iter__'))
print(hasattr(d, '__iter__'))
print(hasattr(t, '__iter__'))
print(hasattr(m, '__iter__'))
print(hasattr(f, '__iter__'))




#########输出结果#######

C:\Python35\python3.exe D:/CODE_FILE/python/day21/迭代器.py
False
True
True
True
True
True

如果大家还是不信,可以继续来测试。我们自己来写一个类,看看有__iter__()方法和没有此方法的区别。

# 没有__iter__()方法
class Animal:
    def __init__(self):
        pass

cat = Animal()

print(isinstance(cat, Iterable))
######输出结果##########

False

# 有__iter__()方法
class Animal:
    def __init__(self):
        pass

    def __iter__(self):
        pass

cat = Animal()

print(isinstance(cat, Iterable))

######输出结果##########

True
  从上面,实验结果可以看出一个对象是否可迭代,关键看這个对象是否有__iter__()方法。

3.迭代器

在介绍迭代器之前,我们先来了解一下容器这个概念。

容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取。简单来说,就好比一个盒子,我们可以往里面存放数据,也可以从里面一个一个地取出数据。

在python中,属于容器类型地有:list,dict,set,str,tuple…。容器仅仅只是用来存放数据的,我们平常看到的 l = [1,2,3,4]等等,好像我们可以直接从列表这个容器中取出元素,但事实上容器并不提供这种能力,而是可迭代对象赋予了容器这种能力。

说完了容器,我们在来谈谈迭代器。迭代器与可迭代对象区别在于:next()方法。

我们可以采用以下方法来验证一下:

from collections import Iterator

f = open('a.txt')
i = 1
s = '1234'
d = {'abc':1}
t = (1, 2, 344)
m = {1, 2, 34, }

print(isinstance(i,Iterator))
print(isinstance(s,Iterator))
print(isinstance(d,Iterator))
print(isinstance(t,Iterator))
print(isinstance(m,Iterator))
print(isinstance(f,Iterator))

########输出结果##########

False
False
False
False
False
True

结果显示:除了文件对象为迭代器,其余均不是迭代器

下面,我们进一步来验证一下:

print(hasattr(i,"__next__"))
print(hasattr(s,"__next__"))
print(hasattr(d,"__next__"))
print(hasattr(t,"__next__"))
print(hasattr(m,"__next__"))
print(hasattr(f,"__next__"))

#######结果###########

False
False
False
False
False
True

从输出结果可以表明,迭代器与可迭代对象仅仅就是__next__()方法的有无。

4.for内部机制剖析

先来看看一段普通的迭代过程:

l = [1,2,3,4,5]
for i in l:
    print(i)

根据之前的分析,我们知道 l = [1,2,3,4,5]是一个可迭代对象。而且可迭代对象是不可以直接从其中取到元素。那么为啥我们还能从列表L中取到元素呢?这一切都是因为for循环内部实现。在for循环内部,首先L会调用__iter__()方法,将列表L变为一个迭代器,然后这个迭代器再调用其__next__()方法,返回取到的第一个值,这个元素就被赋值给了i,接着就打印输出了。

下面,我们通过一系列的实验来证明上述所说的。

l = [1,2,3,4,5,6]
item = l.__iter__()  # 将l变为迭代器
print(item.__next__())  # 迭代器调用next方法,并且返回取出的元素
print(item.__next__())
print(item.__next__())
print(item.__next__())
print(item.__next__())
print(item.__next__())
print(item.__next__())  # 报错
#######输出结果############# 

1 2 3 4 5 6

######上面为什么报错呢??##########
#当调用了最后一个next方法,没有下一个元素可取
#就会报错StopIteration异常错误。你可能会想会
#为什么for循环没有报错?答案很简单,因为for循
#环内部帮我们捕捉到了这个异常,一旦捕捉到异常
#说明,迭代应该结束了!
###########################

上述实验,与我上面说明的一致。

下面,我们可以while循环来模拟for循环,输出列表中的元素。

l = [1,2,3,4,5]

item = l.__iter__()  # 生成一个迭代器

while True:
    try:
        i = item.__next__()
        print(i)
    except StopIteration:  # 捕获异常,如果有异常,说明应该停止迭代
        break

由上分析,我们可以总结出:当我们试图用for循环来迭代一个可迭代对象时候,for循环在内部进行了两步操作:第一,将可迭代对象S变为迭代器M;第二,迭代器M调用__next__()方法,并且返回其取出的元素给变量i。
在这里插入图片描述

你可能看见过这种写法,for i in iter(M):xxx ,其实这一步操作和我们上面没什么区别。iter()函数,就是将一个可迭代对象M变为迭代器也就是M调用__iter__()方法,然后内部在调用__next__()方法。也就是说,

M = [1,2,3,4,5]

for i in iter(M):  # 等价于 M.__iter()__   人为显示调用
    print(i)

for i in M:  # 解释器隐式调用
    print(i)

#################
#
#上面输出的结果完全一样
#
#################

还有,next(M)等价于M.next。

迭代器优点:

  • 1.节约内存

  • 2.不依赖索引取值

  • 3.实现惰性计算(什么时候需要,在取值出来计算)

5.生成器(本质就是迭代器)

什么是生成器?可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法)。

按照我们之前所说的,迭代器必须满足两个条件:既有__iter__(),又有__next__()方法。那么生成器是否也有这两个方法呢?答案是,YES。具体来通过以下代码来看看。

def func():
    print("one------------->")
    yield 1
    print("two------------->")
    yield 2
    print("three----------->")
    yield 3
    print("four------------>")
    yield 4

print(hasattr(func(),'__next__'))
print(hasattr(func(),'__iter__'))

#########输出结果###########

True
True

实验表明,生成器就是迭代器。

Python有两种不同的方式提供生成器:

1.生成器函数(函数内部有yield关键字):常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

既然生成器就是迭代器,那么我们是不是也可以通过for循环来遍历出生成器中的内容呢?看下面代码.

def func():
    print("one------------->")
    yield 1
    print("two------------->")
    yield 2
    print("three----------->")
    yield 3
    print("four------------>")
    yield 4

for i in func():
    print(i)

#########输出结果########

one------------->
1
two------------->
2
three----------->
3
four------------>
4

很显然,生成器也可以通过for循环来遍历出其中的内容。

下面我们来看看生成器函数执行流程:

def func():
    print("one------------->")
    yield 1
    print("two------------->")
    yield 2
    print("three----------->")
    yield 3
    print("four------------>")
    yield 4


g = func()  #  生成器 == 迭代器
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())

每次调用g.next()就回去函数内部找yield关键字,如果找得到就输出yield后面的值并且返回;如果没有找到,就会报出异常。上述代码中如果在调用g.next()就会报错。

Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果。这也是生成器的主要好处。

  • 实例:生成器模拟Linux下tail -f a.txt | grep ‘error’ | grep ‘404’
import time


def tail(filepath):
    with open(filepath, encoding='utf-8') as f:
        f.seek(0, 2)  # 停到末尾开头 1从当前位置  2从文件末尾
        while True:
            line = f.readline()
            if line:  # 如果有内容读出
                #print(line,end='')
                yield line  # 遍历时停在此行,并且将其返回值传递出去
            else:
                time.sleep(0.5)  # 如果文件为空,休眠 等待输入


def grep(lines, patterns):  # lines为生成器类型
    for line in lines:  # 遍历生成器
        if patterns in line:
            yield line


g = grep(tail('a.txt'), 'error')  # 动态跟踪文件新添加的内容,并且过滤出有patterns的行
g1 = grep(g,'404')  # g1为生成器
for i in g1: # 通过for循环来隐式调用__next__()方法
    print(i)

生成器小结:

1.是可迭代对象

2.实现了延迟计算,省内存啊

3.生成器本质和其他的数据类型一样,都是实现了迭代器协议,只不过生成器附加了一个延迟计算省内存的好处,其余的可迭代对象可没有这点好处!

6.可迭代对象、迭代器、生成器关系总结

在这里插入图片描述

7、说明

本文相应的代码及资料已经以.ipynb文件和.pdf形式在github中给出。

github地址:https://github.com/LSayhi/Algorithms

点击【阅读原文】,github传送门
在这里插入图片描述

再来看看Python中的迭代器&生成器 阅读详情

相关推荐

100天精通Python(基础篇)——第27天:迭代器、生成器、装饰器

前言 一、迭代器 1.1 什么是迭代? 1.2 如何判断迭代对象? 1.3 创建迭代器 二、生成器 2.1 什么是生成器? 2.2 创建生成器 方式1 方式2 方式3 2.3 生成器使用案例 处理大量数据 读取大文件 三、装饰器 3.1 什么是闭包

努力让自己发光,对的人才能迎着光而来 20万+

迭代器 Iterator与生成器Generator,从dict.keys()说起

1 beginner https://anandology.com/python-practice-book/iterators.html 2 in-depth http://www.dabeaz.com/generators-uk/

Bismarckczy的博客 1031

STM32低功耗模式下ADC采样抖动的5个隐藏陷阱及解决方案(实测避坑)

本文深入探讨了STM32低功耗模式下ADC采样抖动的5个常见陷阱及解决方案,包括多通道采样电压跃迁、外设开关信号稳定、低功耗模式与ADC时钟同步、输入阻抗失配以及基准电压稳定性问题。通过实测数据和优化代码示例,帮助工程师有效规避ADC采样数据抖动问题,提升物联网设备的测量精度和稳定性。

weixin_30316097的博客 381

区别迭代器和生成器

一:迭代器定义:  迭代器就是实现了迭代器协议的对象。那么小伙伴们就要问了,什么是迭代器协议呢?设计的知识点:  迭代器协议:即对象实现了__iter__()和__next__()两个方法  __iter__()方法:返回迭代器对象本身  __next__()方法:返回容器的下一个元素,在结尾时引发一个StopIteration异常终止迭代器那么迭代器究竟该如何创建呢,创建如下:迭代器的创建:使用...

qq_35187510的博客 1970

Apple CarPlay Certification Guide December 2022 解析V1.0

Apple CarPlay Certification Guide December 2022更新说明

m0_74450450的博客 703

three.js开发3D地图记录(二)

添加地图点击事件,点击区域,地图区域改变颜色并浮起来。

anwebDesigner的博客 1694

Python学习总结-迭代器与生成器

本文通过针对不同应用场景及其解决方案的方式,总结了Python中对迭代器与生成器的一些相关知识。

细嗅蔷薇 1751

RK3576的ISP和VPSS图像处理能力实测:对比海思方案能做什么?

本文深度评测了RK3576芯片的ISP和VPSS图像处理能力,并与海思方案进行对比。测试显示,RK3576在MIPI接口灵活性、多路视频支持、HDR动态范围和降噪效果等方面表现优异,特别适合智能视觉和安防监控应用。通过实测数据展示了其在低照度、高动态范围等复杂场景下的卓越性能。

weixin_42713608的博客 259

Python进阶中迭代器与生成器和数据结构与算法简介

迭代器与生成器、数据结构与算法

wwwwwjjnsnns的博客 1307

零中频接收机实战:DC Offset的5种常见解决方案与调试技巧

本文针对零中频接收机中DC Offset这一核心挑战,深入剖析了其产生机理与对信号解调的严重影响。文章从实战角度出发,系统性地介绍了五种解决方案,包括硬件预防、数字域校正、I/Q不平衡联合校正等,并分享了关键的实验室调试与产线测试技巧,旨在帮助射频工程师有效提升接收机性能。

weixin_29234509的博客 397

思博伦仪表打流测试使用总结

下图红框中的checkbox为选中状态时,表示该流会携带测试仪做一些分析,包括时延和乱序等信息时需要的一些字节,当改选项选中时,如配置IPv4的TCP流,最小字节长度必须为78字节;如果需要64字节的TCP流,改选项必须不选中;

陌上花开缓缓归以的博客 1463

迭代器和生成器&数据结构和算法(基础)

day6 昨天自习没上课,所以今天是第六天,今天这四个内容也是非常的概念,难记得很,晚自习来捋一下思路。

aliedudu的博客 976

(二)OpenClaw-连接即时通讯平台-集成飞书完整配置指南

本文详细介绍了如何将OpenClaw与飞书机器人对接,实现通过飞书聊天窗口下达指令自动执行任务的高效协作模式。主要内容包括:1)OpenClaw服务部署验证和飞书账号准备;2)在飞书开放平台创建企业自建应用、添加机器人能力、获取凭证和开通必要权限;3)OpenClaw服务端的首次配置,包括设置飞书通道参数和启动长连接。文章提供了完整的操作步骤和截图指引,帮助用户快速完成对接配置,实现AI自动化助手功能。

直到世界的尽头 2246

Python的迭代器和生成器

作者:小小明 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/is-subsequence 要解决这个问题,常规算法是贪心算法。我们维护两个指针指向两个字符串的开头,然后对第二个字符串一路扫过去,如果某个字符和第一个指针指的.

小小明-代码实体的专栏 3万+

Valgrind 从入门到精通:内存调试和性能分析

Valgrind 提供了强大的 API,允许开发者编写自定义的检查工具。通过扩展 Valgrind,可以针对特定场景实现更精准的检测。

大模型大数据攻城狮的专栏 1217

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Python 迭代器与生成器、时间复杂度、数据结构

Python中的一个对象;它提供了一个逐个访问集合元素,而不暴露集合的底层实现的方式。协议:需要实现__iter__()和__next__()方法使用:可以通过for循环或next()函数进行遍历。优势:支持惰性计算和高效的内存使用,适合处理大型数据集合或流数据。自定义迭代器:1. 自定义一个类2. 类中必须包含__iter__和__next__方法生成器一种特殊的迭代器,能根据一定规则生成数据;每次调用生成器只生成一个值,以此节省大量内存。

huangch001002的博客 1108

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Python学习笔记(7)迭代器与生成器

在Python编程中,迭代器和生成器都是用于处理序列数据的工具,但它们在概念、实现和使用上有显著差异。下面我将逐步解释它们的区别、实现方式和使用场景,确保内容结构清晰易懂。迭代器和生成器的主要区别在于它们的定义方式和执行机制:迭代器通过定义一个类来实现迭代器协议。以下是实现步骤和一个简单示例: 生成器通过一个函数实现,使用 关键字替代 。函数在每次 时暂停,并返回一个生成器对象。 迭代器和生成器各有适用场景,基于其特性和性能:迭代器和生成器都是Python中处理迭代的核心工具:

2201_75450826的博客 1612

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

迭代器和生成器

ES6 中迭代器和生成器的相关概念与使用。

TKOP_的博客 1236

JS笔记迭代器与生成器

文章目录五、迭代器与生成器5.1 迭代器1 理解迭代2 迭代器模式3 可迭代协议4 迭代器协议5 自定义迭代器6 提前终止迭代器5.2 生成器1 生成器基础2 通过yield中断执行3 生成器作为默认迭代器4 提前终止生成器5.3 总结 五、迭代器与生成器 5.1 迭代器 1 理解迭代 循环是迭代机制的基础,因为它可以指定迭代的次数,以及每次迭代要执行什么操作 数组可以通过递增索引来遍历,但是由于迭代之前需要实现知道如何使用数据结构(数组中的每一项需要先引用取得数组对象,然后通过【】操作符取得索引位置上

qq_18824403的博客 845

JavaScript-迭代器与生成器

在 JavaScript 中,计数循环就是一种最简单的迭代: 迭代会在一个有序集合上进行。(“有序”可以理解为集合中所有项都可以按照既定的顺序被遍历到,特别是开始和结束项有明确的定义。)数组是 JavaScript 中有序集合的最典型例子: 因为数组有已知的长度,且数组每一项都可以通过索引获取,所以整个数组可以通过递增索引来遍历。由于如下原因,通过这种循环来执行例程并不理想:ES5 新增了 方法,向通用迭代需求迈进了一步(但仍然不够理想): 这个方法解决了单独记录索引和通过数组对象取得值的问题。不过,

每天进步一点点 397

七、迭代器与生成器

一、理解迭代: 循环是迭代机制的基础;迭代会在一个有序的集合上进行 通过循环执行迭代并不理想: 迭代之前需要事先知道如何使用数据结构:如数组需要通过索引取值 遍历顺序并不是数据结构固有的 迭代器模式:开发者不需要事先知道如何迭代就能实现迭代操作 二、迭代器模式 迭代器模式:描述了一个方案,把实现了iterable接口的结构称为可迭代对象,可以通过迭代器iterator消费 可迭代对象:包含有限的元素;具有无歧义的遍历顺序 (临时性可迭代对象可以实现为生成器) 迭代器是按需创...

coderxsj 719

Python中的迭代器与生成器提高性能的秘密武器

在Python编程中,迭代器和生成器是提高性能和减少内存消耗的重要工具。它们不仅简化了代码结构,而且在处理大型数据集时具有明显的优势。本文将介绍迭代器和生成器的概念,以及它们如何成为Python中的秘密武器,提高程序的效率。

一键难忘的博客 2870

Python 迭代器与生成器详解:从原理到实战应用

迭代器和生成器是Python处理序列数据的核心工具。迭代器通过iter()创建,使用next()逐个获取元素,遍历后无法重复使用;生成器则通过函数yield或生成器表达式创建,能动态生成数据(包括无限序列),内存效率更高。两者都支持惰性求值,适用于大数据处理,其中生成器还能实现传统数据结构无法完成的无限序列功能。主要区别在于:迭代器依赖已有数据,而生成器通过算法动态生成数据。

qwerty12ljhxjdj的博客 979

优化Python中的数据结构与算法(指南)

Python是一种强大而灵活的编程语言,它提供了丰富的数据结构和算法库,但是在处理大规模数据或者需要高效运行的情况下,需要考虑一些优化技巧。本文将介绍一些Python中常用的数据结构与算法优化技巧,并附带代码实例,帮助你更好地理解和运用。

一键难忘的博客 3256

python的迭代器和生成器

python的迭代器和生成器

一个想交朋友的陌生人 1173
上一篇: 数据结构与算法 学习笔记(1)- 基础知识
下一篇: 数据结构与算法 学习笔记(3)- 表反转与插入排序
LSayhi
博客等级 码龄9年 105粉丝 36原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值