热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python可迭代对象、迭代器和生成器

python可迭代对象、迭代器和生成器目录python可迭代对象、迭代器和生成器一、简介1、关于迭代器和生成器2、关于可迭代对象二、可迭代对象三、迭代器四、生成器与生成器函数1、生

python可迭代对象、迭代器和生成器


目录

  • python可迭代对象、迭代器和生成器
    • 一、简介
      • 1、关于迭代器和生成器
      • 2、关于可迭代对象
    • 二、可迭代对象
    • 三、迭代器
    • 四、生成器与生成器函数
      • 1、生成器函数
      • 2、生成器表达式
    • 五、Reference


一、简介


1、关于迭代器和生成器

关于python的迭代器和生成器这两个概念,大多数程序员都认为其在功能上是类似的,在python官方文档中也有时认为迭代器就是生成器,其实这两种还是有一定的区别。

使用内置函数iter()可以生成迭代器,使用内置函数next()可以获得迭代器中的值。

第一点,从概念上:
在典型的迭代器设计模式中,迭代器用于遍历集合,从中产出元素,迭代器不能修改数据源中的值,只能原封不动地产出,而生成器可能无需遍历就能生成值。

第二点,从接口方面:
python的迭代器协议定义了两个方法__iter____next__,生成器实现了这两个方法,因此从这方面来看,所有的生成器都是迭代器。

第三点、从实现方面:
生成器这种python语言结构可以使用两种方式编写:1、含有yield关键字的函数,称之为生成器函数。2、使用生成器表达式。


2、关于可迭代对象

为什么是可迭代的?

在介绍可迭代对象之前,我们先了解一下python中序列可迭代的原因,序列之所以可以迭代是因为iter()内置函数,iter()内置函数有以下作用:

(1) 检查对象是否实现了__iter__方法,如果实现了就调用它,获取一个迭代器

(2) 如果没有实现__iter__方法,但是实现了__getitem__方法,python会创建一个迭代器,尝试按照顺序(从索引0)开始获取元素。

(3) 如果上述尝试均失败,python会抛出TypeError异常

什么是可迭代对象?

按照上面python序列可迭代的原因来看,Python中任意的对象,只要它定义了可以返回一个迭代器的 __iter__ 方法,或者定义了可以支持下标索引的 __getitem__ 方法,那么它就是一个可迭代对象。简单说,可迭代对象就是能提供迭代器的任意对象。


二、可迭代对象


可迭代对象可以使用内置iter()函数获取迭代器的对象,如果对象实现了能返回迭代器的__iter__方法,那么对象就是可以迭代的。序列都可以迭代;实现了__getitem__方法,而且其参数是从零开始的索引,这种对象也可以迭代。


按照上面我们对可迭代对象的定义,我们进行如下代码实验

import re
import reprlibRE_WORD = re.compile('\w+')class Sentence(object):def __init__(self, text):self.text = textself.words = RE_WORD.findall(text) # re.findall函数返回一个字符串列表,得到匹配的单词# 我们只实现了__getitem__方法def __getitem__(self, index):return self.words[index]def __repr__(self):return 'Sentence(%s)' % reprlib.repr(self.text)s = Sentence('My favorite language is python !')
print(s)
# 我们迭代打印s中的值,打印成功则Sentence类是可以迭代的
for word in s: print(word)

Sentence('My favorite ...e is python !')
My
favorite
language
is
python

在上述代码实验中,我们并没有重载__itet__方法,而是重载了__getitem__方法,我们自定义的Sentence类仍然是可以迭代的,说明我们之前对可迭代对象的定义正确。

我们来验证是否能够使用iter()内置函数来直接获取对象的迭代器,

s1 = Sentence('Hi Python')
it = iter(s1) # 获取序列的迭代器对象
print(next(it))
print(next(it))

Hi
Python

结果表明,我能确实能够获得序列对象的迭代器。


三、迭代器

标准的迭代器需要实现的方法:


(1) __next__ 返回下一个可用的元素,如果没有元素,抛出StopIteration异常。

(2) __iter__ 返回self,以便在应该使用可迭代对象的地方使用迭代器,例如for循环中。
在这里插入图片描述


现在我们按照迭代的标准写法,来改写前一个列子的代码。

import re
import reprlibRE_WORD = re.compile('\w+')class Sentence(object): # 可迭代对象实现__iter__def __init__(self, text):self.text = textself.words = RE_WORD.findall(text)def __repr__(self):return "Sentence(%s)" % reprlib.repr(self.text)def __iter__(self):return SentenceIterator(self.words)class SentenceIterator(object): # 迭代器实现__next__和__iter__def __init__(self, words):self.words = wordsself.index = 0def __next__(self):try:word = self.words[self.index]except IndexError:raise StopIterationself.index += 1return worddef __iter__(self):return selfs1 = Sentence('My favorite language is Python!')
print(s1)
print('================================')for word in s1: print(word)it = iter(s1)
print('================================')
print(next(it))
print(next(it))

Sentence('My favorite ...ge is Python!')
================================
My
favorite
language
is
Python
================================
My
favorite

在构建迭代器对象和迭代器时经常会出现错误,原因是混淆了两者,要知道,可迭代的对象有一个__iter__方法,每次都实例化一个新的迭代器;而迭代器要实现__next__方法,返回单个元素,此外还要实现__iter__方法,返回迭代器本身。


小结:
可迭代的对象一定不能是自身的迭代器,也就是说,可迭代的对象必须实现__iter__方法,但是不能实现__next__方法。
另一方面,迭代器应该可以一直迭代,迭代器的__iter__方法应该返回自身。



四、生成器与生成器函数


1、生成器函数


先介绍什么是生成器函数,在普通函数定义中,不需要return,而是采用yield关键字来“产生”值,该函数就是生成器函数。调用生成器函数时,会返回一个生成器对象,也就是说生成器函数是生成器工厂。


定义一个简单的生成器函数:

def gen_123():for i in [1,2,3]:yield iit = gen_123()
print(next(it))
print(next(it))
print(next(it))

1
2
3

上述代码中,为了实现相同的功能,符合python编程风格的做法是,用生成器函数来代替SentenceIterator类

import re
import reprlibRE_WORD = re.compile('\w+')class Sentence(object): # 可迭代对象实现__iter__def __init__(self, text):self.text = textself.words = RE_WORD.findall(text)def __repr__(self):return "Sentence(%s)" % reprlib.repr(self.text)def __iter__(self): # 替换成生成器函数for word in self.words:yield words2 = Sentence('My favorite language is Pythooooon!')
print(s2)
print('================================')for word in s2: print(word)
print('================================')it = iter(s2)
print(next(it))
print(next(it))

Sentence('My favorite ...s Pythooooon!')
================================
My
favorite
language
is
Pythooooon
================================
My
favorite

注意我们在此,并没有定义迭代器类,而是使用生成器函数来代替迭代器的类,更加pythonic


2、生成器表达式

生成器表达式,和列表生成式字典生成式等类似,只不过将[ ]替换成( )

it = (x for x in [1,2,3,4])
print(type(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))

<class &#39;generator&#39;>
1
2
3
4

五、Reference

https://www.liaoxuefeng.com/wiki/1016959663602400/1017318207388128
https://www.runoob.com/python3/python3-iterator-generator.html
https://py.eastlakeside.cn/book/DataStructures/generators.html
《FluentPython》


推荐阅读
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
author-avatar
了不起的老狐_226
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有