当前位置: 首页 > news >正文

python将list转换为迭代器代码_Python进阶内容(四)--- 迭代器(Iterator)与生成器(Generator)...

迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

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

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

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

注意:在Python3中,next(Iterator)实际上调用的是Iterator.__next__(),在表述上可以认为两者等价。next()是内建函数,__next__()是Iterator的方法。

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

>>> from collections importIterable>>>isinstance([], Iterable)

True>>>isinstance({}, Iterable)

True>>> isinstance('abc', Iterable)

True>>> isinstance((x for x in range(10)), Iterable)

True>>> isinstance(100, Iterable)

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

>>> from collections importIterator>>> isinstance((x for x in range(10)), Iterator)

True>>>isinstance([], Iterator)

False>>>isinstance({}, Iterator)

False>>> isinstance('abc', Iterator)

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

>>>isinstance(iter([]), Iterator)

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

True

Q:为什么list、tuple、dict、set、str等数据类型不是Iterator?

A:Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration异常。非要类比的话,赌场发牌的荷官算是一个比较接近的例子。本来你需要自己去处理一堆牌(list、tuple、dict等iterable),现在你有了这个对象,只要不断问他要“下一张”,他要是有自然会给你,没有就结束(StopIteration)。

iter 函数

Python提供了一个iter函数用来生成迭代器。这个方法有两个参数,当只传入一个参数的时候:

若这个参数是一个容器,则返回这个容器的迭代器对象,

若这个参数本身就是一个迭代器,则返回其自身,

In [1]: alist = [1, 2, 3, 4]

In [2]: it =iter(alist)

In [3]: it

Out[3]: In [4]: it2 =iter(it)

In [5]: id(it) ==id(it2)

Out[5]: True

iterator 的特点

迭代器都有一个__next__方法,调用了__next__方法之后,迭代指针会指向下一个元素的位置,若下一个元素没有了,则会抛出StopIteration异常。

In [09]: alist = [1, 2, 3, 4]

In [10]: it =iter(alist)

In [11]: it.__next__()

Out[11]: 1In [12]: it.__next__()

Out[12]: 2In [13]: next(it) #也可以使用内建函数next(iterator)完成这一功能

Out[13]: 3In [14]: next(it)

Out[14]: 4In [15]: next(it)---------------------------------------------------------------------------StopIteration Traceback (most recent call last) in ()----> 1next(it)

StopIteration:

In [16]:

了解了这些情况以后,我们就能使用迭代器进行遍历了。

it = iter([1, 2, 3, 4])try:whileTrue:

val= it.__next__()print(val)exceptStopIteration:pass

#实际上由于迭代操作如此普遍,Python专门将关键字for用作了迭代器的语法糖。#在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用__next__()获取元素,还完成了检查StopIteration异常的工作。#上述代码可以写成如下的形式,你一定非常熟悉:

for val in [1, 2, 3, 4]:print(val)#首先Python将对关键字in后的对象调用iter函数获取迭代器,然后调用迭代器的next方法获取元素,直到抛出StopIteration异常。#对迭代器调用iter函数时将返回迭代器自身,所以迭代器也可以用于for语句中,不需要特殊处理。#常用的几个内建数据结构tuple、list、set、dict都支持迭代器,字符串string也可以使用迭代操作。

for val in iter([1, 2, 3, 4]):print(val)

使用迭代器的循环可以避开索引,但有时候我们还是需要索引来进行一些操作的。这时候内建函数enumerate就派上用场,用起来就像这样:

for idx in enumerate(['a','b','c','d']):print(idx)#输出结果

(0, 'a')

(1, 'b')

(2, 'c')

(3, 'd')

iterator 的定义

对于上面的 it 这个迭代器,是通过 iter方法实现的,那么iter函数到底做了什么呢?简而言之,实现了迭代器协议的对象就是迭代器。什么是迭代器协议呢?再简而言之,满足下面两个条件即可:

实现 __iter__()方法,返回一个迭代对象,

实现 __next__() 方法,返回当前的元素,并指向下一个元素的位置,当前位置已经没有元素的时候,抛出StopIteration异常。

注意:内建函数iter和__iter__方法两者的关系,类似于内建函数next和__next__方法之间的关系。

#下面我们实现一个迭代器对象,要求可以进行逆序迭代。

classReverseList:def __init__(self, item):

self.list=itemdef __iter__(self):returnselfdef __next__(self):try:returnself.list.pop()exceptIndexError:raiseStopIterationif __name__ == "__main__":

it= ReverseList([1, 2, 3, 4])for i init:print(i)#输出结果

4

3

2

1

下面的例子用到了 迭代器迭代后销毁元素 这一性质,

#以下代码演示了如何利用zip函数和迭代器对列表中的元素进行分组

defgroup_adjacent(x, k):

result= [iter(x)] * k #result = [, , ]

return zip(*result) #解包 包含三个迭代器的列表,并利用zip函数进行归类,从而返回一个可迭代对象zip

alist= ["foo", 2, "bar", 4, "far", 6]for inx in group_adjacent(alist, 3):print(inx)#输出结果

('foo', 2, 'bar')

(4, 'far', 6)

迭代器(Iterator)小结

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

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

Python中for...in循环本质上是通过不断调用__next__()函数实现的,可以视作迭代器的语法糖

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

迭代器不要求你事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。这个特点被称为延迟计算或惰性求值(Lazy evaluation)。

生成器

生成器本质上就是一个迭代器,它有和迭代器一样的特性,唯一的区别在于实现方式上不一样,生成器更加简洁。

#一种方式是 生成器表达式(Generator expression)

l= [x * x for x in range(10)] #列表解析(List Comprehension)

g = (x * x for x in range(10)) #生成器表达式(Generator expression)

print(l) #输出:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

print(g) #输出: at 0x10e7a0a40>

In [20]: g.__next__()

Out[20]: 0

In [21]: g.__next__()

Out[21]: 1In [22]: g.__next__()

Out[22]: 4In [23]: g.__next__()

Out[23]: 9In [24]: g.__next__()

Out[24]: 16In [25]: l.__next__()---------------------------------------------------------------------------AttributeError Traceback (most recent call last) in ()----> 1 l.__next__()

AttributeError:'list' object has no attribute '__next__'

#另一种方式是generator function,如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。#普通函数是顺序执行,遇到return语句,或者执行完所有函数块内的语句就返回。

# generator function是在每次调用__next__()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

In [27]: defget_square(n):

...:for x inrange(n):

...:yield x ** 2 #每次迭代时返回 x ** 2,然后挂起

...:

In [28]: f = get_square(10)

In [29]: f

Out[29]: In [30]: f.__next__()

Out[30]: 0

In [31]: f.__next__()

Out[31]: 1In [32]: f.__next__()

Out[32]: 4

我们来看一个例子,使用生成器返回自然数的平方(注意返回的是多个值),

#使用普通函数

defgensquares(N):

res=[]for i inrange(N):

res.append(i*i)returnresfor item in gensquares(5):print(item)#使用生成器函数

defgensquares(N):for i inrange(N):yield i ** 2

for item in gensquares(5):print(item)#通过对比发现,使用生成器代码更少,惰性计算也使得程序性能更好

生成器小结

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

生成器表达式:类似于列表解析,但是它们返回按需产生结果的一个对象,而不是构建一个结果列表

生成器函数:编写为常规的def语句,但是使用yield语句一次返回一个结果,在每个结果之间挂起和继续它们的状态

生成器在协程(coroutine)中发挥了重要作用,协程(coroutine)一般来说是指这样的函数:

彼此间有不同的局部变量、指令指针,但仍共享全局变量;

可以方便地挂起、恢复,并且有多个入口点和出口点;

多个协同程序间表现为协作运行,如A的运行过程中需要B的结果才能继续执行。

我们将在后面的内容中继续详细介绍yield和协程的内容.

额外补充:

Python内置了一个模块itertools,包含了很多函数用于creating iterators for efficient looping(创建更有效率的循环迭代器),详见官方文档。

classPipe:def __init__(self, func):

self.func=funcdef __ror__(self, other):print(other)defgenerator():for obj inother:if obj is notNone:yieldself.func(obj)returngenerator()

@Pipedefeven_filter(num):return num if num % 2 == 0 elseNone

@Pipedefmultiply_by_three(num):return num * 3@Pipedefconvert_to_string(num):return 'The Number: %s' %num

@Pipedefecho(item):print(item)returnitemdefforce(sqs):for item in sqs: passnums= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]if __name__ == "__main__":

force(nums| even_filter | multiply_by_three | convert_to_string | echo)

内容小结:

可迭代对象(Iterable)是实现了__iter__()方法的对象,通过调用iter()方法可以获得一个迭代器(Iterator)

迭代器(Iterator)是实现了__iter__()和__next__()的对象

for ... in ...的迭代,实际是将可迭代对象转换成迭代器,再重复调用next()方法实现的

生成器(generator)是一个特殊的迭代器,它的实现更简单优雅.

yield是生成器实现__next__()方法的关键.它作为生成器执行的暂停恢复点,可以对yield表达式进行赋值,也可以将yield表达式的值返回.

推荐阅读:

相关文章:

  • python路测是什么_路测是怎样的一种工作体验?
  • python 隐马尔科夫_Python的隐马尔科夫HMMLearn库的应用教学
  • 电容过大导致电压下降_关于补偿电容,你又了解多少呢?
  • 填谷式无源pfc电路_分析PFC并用于对电机控制解决
  • 怎么实现角色权限的分配_新生日记2“铁血妈妈”刘璇和“艺术慈父”王弢,你家角色怎么分配?...
  • adm 客户机禁止使用cpu_2021适合女士使用的轻薄笔记本电脑、性价比高的平板电脑推荐(送女友老婆情人节生日礼物)...
  • viterbi算法_Lyft推出一种新的实时地图匹配算法
  • 怎么把做好的ps保存成图片_PS保存图片提示“无法完成请求”,这里有4种解决方法...
  • python 接口自动化测试 pdf_Python接口自动化测试实战
  • python word2vec库_使用Python可视化Word2vec的结果
  • python标准库生成随机数_数字和数学模块 - random —- 生成伪随机数 - 《Python 3.7 标准库》 - 书栈网 · BookStack...
  • vscode python自动补全插件_基础讲解:VSCode中自动为Python文件添加头部注释
  • 交换机工作原理_交换机、路由器如何传输?网速慢是什么原因?两个视频了解清楚...
  • word 代码块_word中快速去除文档中的超链接网址
  • zabbix安装部署windows_zabbix、cacti、nagios,服务器监控还有更好的选择吗?
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • EventListener原理
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • MobX
  • MySQL QA
  • Python中eval与exec的使用及区别
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • SQLServer之索引简介
  • TypeScript迭代器
  • Vue全家桶实现一个Web App
  • 树莓派 - 使用须知
  • 数据仓库的几种建模方法
  • 我从编程教室毕业
  • 小程序开发之路(一)
  • 新书推荐|Windows黑客编程技术详解
  • 用 Swift 编写面向协议的视图
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • #{}和${}的区别是什么 -- java面试
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (arch)linux 转换文件编码格式
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (二)fiber的基本认识
  • (四)汇编语言——简单程序
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • .gitignore文件---让git自动忽略指定文件
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • .net中生成excel后调整宽度
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(白虎组)
  • []C/C++读取串口接收到的数据程序
  • [ActionScript][AS3]小小笔记
  • [AIR] NativeExtension在IOS下的开发实例 --- IOS项目的创建 (一)
  • [C#]winform利用seetaface6实现C#人脸检测活体检测口罩检测年龄预测性别判断眼睛状态检测
  • [caffe(二)]Python加载训练caffe模型并进行测试1
  • [gdc19]《战神4》中的全局光照技术
  • [Google Guava] 1.1-使用和避免null
  • [HDU 3555] Bomb [数位DP]
  • [Java]快速入门优先队列(堆)手撕相关面试题
  • [java]删除数组中的某一个元素