python入门学习笔记之生成器&迭代器

自学Python之列表(含义+示例+访问列表元素) 含义 列表由一系列按特定顺序排列的元素组成。列表用方括号[]表示,同时[]中储存数据,用逗号分隔元素,逗号后要加一个空格的距离。 任何东西都可以加入列表中,其中的元素可以没有任何关系。(即变量、字符串、整数等都可以加入到列表中,元素之间相互独立。) 通常给列表指定复数的名称,如letters, friends. 列表示例 列表中元素要用引号引起。 访问列表元素 列表是有序元素的集合,要访问列表元素,需要将该元素的位置或索引告诉Python.Python的索引从0开始计算,... 阅读详情

本节重点:

使学生掌握列表生成式、生成器、迭代器
本节时长需控制在 分钟内

列表生成式
现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求你把列表里的每个值加1,你怎么实现?你可能会想到2种方式

二逼青年版

>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b = []
>>> for i in a:b.append(i+1)
... 
>>> b
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = b
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

普通青年版

a = [1,3,4,6,7,7,8,9,11]

for index,i in enumerate(a):
    a[index] +=1
print(a)

文艺青年版

>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = map(lambda x:x+1, a)
>>> a
<map object at 0x101d2c630>
>>> for i in a:print(i)
... 
3
5
7
9
11

其实还有一种写法,如下

装逼青年版

>>> a = [i+1 for i in range(10)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

这样的写法就叫做列表生成式

生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>

创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

我们讲过,generator保存的是算法,每次调用next(g)就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

当然,上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:

>>> g = (x * x for x in range(10))
>>> for n in g:
...     print(n)
...
0
1
4
9
16
25
36
49
64
81

所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'

注意,赋值语句:

a, b = b, a + b

相当于:

t = a + b 
a = b 
b = t

但不必显式写出临时变量t就可以赋值。

上面的函数可以输出斐波那契数列的前N个数:

>>> fib(10)
1
1
2
3
5
8
13
21
34
55
done

仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

def fib(max):
    n,a,b = 0,0,1

    while n < max:
        #print(b)
        yield  b
        a,b = b,a+b

        n += 1

    return 'done'

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次被next()调用时从上次返回的yield语句处继续执行。

data = fib(10)
print(data)

print(data.__next__())
print(data.__next__())
print("干点别的事")
print(data.__next__())
print(data.__next__())
print(data.__next__())
print(data.__next__())
print(data.__next__())

#输出
<generator object fib at 0x000002E33EEFFCA8>
1
1
干点别的事
2
3
5
8
13

在上面fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

>>> for n in fib(6):
...     print(n)
...
1
1
2
3
5
8

但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:

>>> g = fib(6)
>>> while True:
...     try:
...         x = next(g)
...         print('g:', x)
...     except StopIteration as e:
...         print('Generator return value:', e.value)
...         break
...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done

关于如何捕获错误,后面的错误处理还会详细讲解。

还可通过yield实现在单线程的情况下实现并发运算的效果

#_*_coding:utf-8_*_
__author__ = 'Alex Li'

import time
def consumer(name):
    print("%s 准备吃包子啦!" %name)
    while True:
       baozi = yield

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))


def producer(name):
    c = consumer('A')
    c2 = consumer('B')
    c.__next__()
    c2.__next__()
    print("老子开始准备做包子啦!")
    for i in range(10):
        time.sleep(1)
        print("做了2个包子!")
        c.send(i)
        c2.send(i)

producer("alex")

通过生成器实现协程并行运算
迭代器
我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如list、tuple、dict、set、str等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。

可以使用isinstance()判断一个对象是否是Iterable对象:

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

可以使用isinstance()判断一个对象是否是Iterator对象:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。

把list、dict、str等Iterable变成Iterator可以使用iter()函数:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

你可能会问,为什么list、dict、str等数据类型不是Iterator?

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

Python3的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
    pass

实际上完全等价于:

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break
再来看看Python中的迭代器&生成器 阅读详情

相关推荐

保姆级教程:用Docker Compose在Linux上一键部署Milvus 2.5.8(附配置文件详解)

本文提供了一份详细的Milvus 2.5.8安装指南,通过Docker Compose在Linux系统上一键部署这款高性能向量数据库。教程涵盖环境准备、配置文件解析、服务启动验证及常见问题解决,帮助开发者快速搭建AI应用所需的基础设施。

weixin_28829629的博客 269

Python高级特性(生成式与生成器)

1.列表生成式 列表生成式就是一个用来生成列表的特定语法形式的表达式。是python提供的一种生成列表的简洁形式,可快速生成一个新的列表 1).普通语法格式: [exp for iter_var in iterable] 例如:生成一个2n+1的数字列表,n为从3到11的数字 list=[2*i+1 for i in range(3,12)] 2).带过滤功能语法格式: [exp for i...

qq_40102768的博客 565

nvlddmkm事件ID14报错排查全指南:从找不到描述到显卡驱动崩溃

系统日志中的“无法找到描述”往往让人一头雾水,但这类提示其实隐藏着驱动故障的关键线索。Windows事件查看器通过事件源和ID记录系统异常,其中显卡驱动相关的内核模式驱动组件一旦超时失败,就会触发TDR机制,产生13、14、153等不同事件ID。理解这些ID的含义,比纠结“找不到描述”本身更重要。对于频繁出现的驱动崩溃问题,可以从日志频率和发生场景判断方向,再通过安全模式下彻底清理驱动、关闭冲突软件、检查供电和温度等步骤逐层定位。无论是游戏满载黑屏,还是睡眠唤醒后闪退,掌握NVIDIA驱动日志的解读逻辑,都

weixin_30545945的博客 414

python:列表生成式

python列表生成式(List Comprehensions): 公式: [expression for i in 序列 if…] [要的结果+判断条件] 1.是Python内置的非常简单却强大的可以用来创建list的生成式。 2.将条件和返回写在列表中一行完成 举例说明: 当我们想要得到需要循环才能实现的内容时:输出1-10的各个数的对应次方的值。1的1次方,2的2次方,3的3次方… 通过...

dddxxy的博客 1134

Linux中Hadoop 集群搭建

零、下载Hadoop: http://archive.cloudera.com/cdh5/cdh/5/?tdsourcetag=s_pctim_aiomsg 一、集群规划: 搭建的 hadoop 集群由 3 台服务器组成,分别叫做 master,salve1 和 slave2。其中 master 作为主节点,slave1 和 slave2 作为从节点。 二、网络配置: 1.查看 3 个节点的主机名...

白墨的小白博客 3992

《深入浅出强化学习原理入门》学习笔记(三)机器人找金币应用实例

《深入浅出强化学习原理入门》学习笔记(三)MDP应用实例

lxs3213196的博客 3187

修改列表生成式,使列表中的字符串小写

如果list中既包含字符串,又包含整数,由于非字符串类型没有lower()方法,所以列表生成式会报错.使用内建的isinstance函数可以判断一个变量是不是字符串: &gt;&gt;&gt; x = 'abc' &gt;&gt;&gt; y = 123 &gt;&gt;&gt; isinstance(x, str) True &gt;&gt;&gt; isinstance(y, str) False 请修改列表生成式,通过添加if语句保证列表生成式能正确地执行:(当时写的) L1 = ['Hello',

weixin_43938663的博客 228

Ubuntu 20.04 系统备份和还原

最近大家Ubuntu开发环境,经常出现搭着搭着系统就挂了,于是开始琢磨了Ubuntu系统的备份和还原,以备不时之需,Linux环境搭建实在是有点太细,好多情况下,就算曾经搭建过一遍,再次搭建有些包还是忘了安装,做好备份是十分必要的。 经过了一番研究,Ubuntu备份有很多方式:根目录tar、dd、Systemback(1.0版本已经不维护了,2.0版本收费)等等,最终决定使用 —— Timesift, 因为方便一些。 文章参考:小马虎的救星——Timeshift Timeshift Timeshift,是L

Z_Paper的博客 2万+

43 列表的操作——访问列表元素及遍历

文章目录1、访问列表元素2、遍历 1、访问列表元素 2、遍历

Blog of Lytracy 4613

详解电路设计中的RC电路

​ 一、什么是RC电路 RC电路是指由电阻R和电容C组成的电路,它是脉冲产生和整形电路中常用到 的电路。 常见的RC充、放电电路、RC积分电路合RC微分电路接下来详细讲解。 二、RC充、放电电路 RC充、放电电路如下图所示,下面通过充电和放电两个过程来分析此电路。 ​RC充、放电电路图 (1)RC充电电路 RC充电电路图如下图(a)所示 RC充电电路图及充电曲线图 ​由上图分析: 将上图a中开关S置于“1”处,电源E开始通过电阻R对电容C充电,由于刚开始充电时电容两端没有..

IT xiaobai 4万+

harbor x509: certificate signed by unknown authority【20251222】

本教程通过「合并证书链(服务器端)+ 预置根 CA(客户端)」彻底解决了自签名证书的 x509 错误,同时集成了 Trivy 漏洞扫描,实现了 Harbor 从搭建到实用的全流程。证书链合并是服务器端的关键,确保客户端获取完整信任路径;客户端需同时配置「系统信任库 + Docker 信任目录」,避免 Docker 独立信任机制导致的问题;所有 IP 需保持一致(Harbor 配置、证书绑定、客户端访问),是避免错误的基础。

老韩的Linux云计算架构师进阶之路 681

Python入门学习笔记:函数式编程&迭代器与生成器&异常处理

必须有一个内嵌函数内嵌函数必须引用外部函数中变量外部函数返回值必须是内嵌函数# 自定义迭代器类​return self # 迭代器返回自身​else:raise StopIteration # 数据迭代结束​# 使用自定义迭代器。

PQI_JiXian的博客 985

COMSOL有限元仿真深度指南:为结构件添加预应变

一、什么是预应力和预应变? 我们知道,结构力学问题中,结构件在外载荷作用下产生变形响应以吸收外载荷做功带来的能量;而在结构内部,整体的受力和变形则是通过固体微元的应力与应变传递的。 对于线弹性材料来说,应力与应变的关系可以线性表达,也即 σ=Dεσ = Dεσ=Dε ;在该式中,无论固体微元的应变程度多大,弹性矩阵DDD都是一个不变的常值。而对于超弹性材料来说,应力与应变的关系则需要通过应变能密度函数WWW来表征(详细参加博客《COMSOL有限元仿真深度指南:超弹性模型有限元分析入门》)。 从上面我们也不难

忘了面孔的Batou 7170

python迭代器和生成器

帮助大家深入了解迭代器与生成器

qq_52758588的博客 1万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Python迭代器和生成器

方法_iter_返回一个迭代器,它是包含方法_next_的对象,而调用这个方法可以不提供任何参数。推荐在迭代器中也实现方法__iter__(并像刚才那样使它返回self),这样迭代器就可以直接用于for循环。在可以使用序列的情况下,大多数也可使用迭代器或可迭代对象,可以使用构造函数list显示地将迭代器转化为列表。迭代器实现了方法__iter__,这个方法返回迭代器本身,大多数情况下,都在。对象中实现返回迭代器的方法__iter__,并在for循环中使用这个对象。实现了方法__iter__的对象是。....

m0_73076093的博客 6994

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Python入门:生成器&迭代器

通过列表生成式,可以直接创建一个列表,但是,受到内存限制,列表容量是有限的,而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数占用的空间都白白浪费了。Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。你可能会想到2种方式。观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

Trb401012的博客 1041

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Python 迭代器与生成器

在Python当中:迭代器是实现迭代器协议的对象,它包含方法__iter__()和__next__()

m0_74995879的博客 1652

python 迭代器&生成器

python 迭代器&生成器

喵酱 1943

Python入门——yield生成器和iter迭代器

yield关键字让你可以创建生成器函数,用于逐步生成值,而不是一次性生成所有值。生成器可以用于高效处理大量数据或实现惰性求值。iter迭代器在 Python 中,迭代器(Iterator)是一个可以记住遍历位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完毕后结束。迭代器只能往前走,不能回退。迭代器是一种可以记住访问位置的对象,遵循迭代器协议(__iter__()和__next__()方法)。迭代器可以高效地处理数据流,避免将整个数据集一次性加载到内存中。

m0_74893204的博客 1684

python 之 迭代器、生成器、装饰器

生成器是创建迭代器的一种更简单、更优雅的方式。不需要去写一个完整的类并实现__iter__()和__next__()方法。只需要写一个普通的函数,但是使用 yield关键字而不是return来返回值。

weixin_44929150的博客 1402

Python进阶————迭代器与生成器

Python中的迭代器与生成器的区别与联系

记录学习笔记 2178

python生成器与迭代器

迭代器用于从集合中取出元素,生成器用于凭空生成元素;iter()方法可以获取一个迭代器(_iter__或如果实现了__iter__方法,对象就是可迭代的;使用iter(a)可判断a是否可迭代,不可迭代会报错(或isinstance(a, abc.iterable) (from collections import abc));可迭代对象与迭代器关系:Python从可迭代的对象中获取迭代器。

weixin_46287157的博客 1664

Python 迭代器和生成器

Python 迭代器和生成器

tangsiqi130的博客 1271

18.从入门到精通:Python迭代器与生成器 迭代器 创建一个迭代器 StopIteration 生成器

接着,我们使用next()函数获取迭代器it的下一个元素,依次输出1、2、3。在这个例子中,我们使用while循环和try-except语句遍历迭代器it,每次迭代都会尝试获取下一个元素,直到遍历完所有元素为止。在这个例子中,我们使用for循环遍历列表nums,每次迭代都会自动调用next()函数获取下一个元素,直到遍历完所有元素为止。这使得生成器非常适合处理大量数据或无限序列。在这个例子中,我们使用for循环遍历列表nums,每次迭代都会自动调用next()函数获取下一个元素,直到遍历完所有元素为止。

weixin_63740705的博客 4420
上一篇: python入门开发笔记之函数进阶
下一篇: python入门开发笔记之模块、包介绍和相关介绍
程序员_大白
博客等级 码龄5年 1万+粉丝 4001原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值