一文读懂Python可迭代对象、迭代器和生成器

IT头条

每日推送最新、最热点的IT界新闻

马化腾回应“腾讯没有梦想”截图系网友PS;天天P图回应《我的前世青年照》涉嫌收集个人隐私;马云称阿里不愿招北大清华毕业生……

----【IT服务圈儿报】第74期

源 / Python中文社区     文 / 无名小妖

我们都知道,序列可以迭代。但是,你知道为什么吗? 本文来探讨一下迭代背后的原理。

序列可以迭代的原因:iter 函数。解释器需要迭代对象 x 时,会自动调用 iter(x)。内置的 iter 函数有以下作用:

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

(2) 如果没有实现 iter 方法,但是实现了 getitem 方法,而且其参数是从零开始的索引,Python 会创建一个迭代器,尝试按顺序(从索引 0 开始)获取元素。

(3) 如果前面两步都失败,Python 抛出 TypeError 异常,通常会提示“C objectis not iterable”(C 对象不可迭代),其中 C 是目标对象所属的类。

由此我们可以明确知道什么是 可迭代的对象: 使用 iter 内置函数可以获取迭代器的对象。即要么对象实现了能返回迭代器的 iter 方法,要么对象实现了 getitem 方法,而且其参数是从零开始的索引。

下面看一个实现了getitem方法的例子:

class Eg1:
  def __init__(self, text):
      self.text = text
      self.sub_text = text.split(' ')

def __getitem__(self, index):
      return self.sub_text[index]

o1 = Eg1('Hello, the wonderful new world!')
for i in o1:
  print(i)

输出结果:

Hello,thewonderfulnewworld!

我们创建了一个类Eg1,并且为这个类实现了 getitem 方法, 它的实例化对象o1 就是可迭代对象。

下面我们看一个实现 iter 方法的例子,因为用到了迭代器,所以在此我们必须在明确一下迭代器的用法。 标准的迭代器接口有两个方法:

__next__

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

__iter__

返回 self,以便在应该使用可迭代对象的地方使用迭代器,例如在 for 循环中。

class Eg2:
  def __init__(self, text):
      self.text = text
      self.sub_text = text.split(' ')

def __iter__(self):
      return Eg2Iterator(self.sub_text)

class Eg2Iterator:
  def __init__(self, sub_text):
      self.sub_text = sub_text
      self.index = 0

def __next__(self):
      try:
          subtext = self.sub_text[self.index]
      except IndexError:
          raise StopIteration()
      self.index += 1
      return subtext

def __iter__(self):
      return self

我们创建了Eg2类,并为它实现了 iter 方法,此方法返回一个迭代器Eg2Iterator。 Eg2Iterator 实现了我们之前所说的next和iter方法。 实例化对象,并循环输出:

o2 = Eg2('Hello, the wonderful new world!')for i in o2:  print(i)Hello,thewonderfulnewworld!

可见,和o1是一样的。

我们通过两种方法实现了一个自己的可迭代对象,再此过程中我们要明确可迭代的对象和迭代器之间的关系:

Python 从可迭代的对象中获取迭代器。

iter方法从我们自己创建的迭代器类中获取迭代器,而getitem方法是python内部自动创建迭代器。

至此,我们明白了如何正确地实现可迭代对象,并且引出了怎样实现迭代器,但是使用迭代器方法(即上面的例子2)的代码量有点大,下面我们来了解一下如何使用更符合 Python 习惯的方式实现 Eg2类。

class Eg3:
  def __init__(self, text):
      self.text = text
      self.sub_text = text.split(' ')

def __iter__(self):
      for item in self.sub_text:
          yield item

哦了!就这么简单优雅!不用再单独定义一个迭代器类!

这里我们使用了yield 关键字, 只要 Python 函数的定义体中有 yield 关键字,该函数就是生成器函数。调用生成器函数时,会返回一个生成器对象。也就是说,生成器函数是生成器工厂。 当然,例子3的代码还可以使用yield from进一步简化:

class Eg4:  def __init__(self, text):      self.text = text      self.sub_text = text.split(' ')

  def __iter__(self):      yield from self.sub_texto4 = Eg4('Hello, the wonderful new world!')for i in o4:  print(i)Hello,thewonderfulnewworld!

到这里我们明白了 可迭代对象 和 迭代器,还引申出了生成器,但还有一点没有提,那就是生成器表达式。

使用生成器表达式例子4的代码可以修改为:

class Eg5:
  def __init__(self, text):
      self.text = text
      self.sub_text = text.split(' ')

def __iter__(self):
      return (item for item in self.sub_text)

在python中,所有生成器都是迭代器。

最后,总结一下:

(1)什么是可迭代对象? 可迭代对象要么实现了能返回迭代器的 iter 方法,要么实现了 getitem 方法而且其参数是从零开始的索引。

(2)什么是迭代器? 迭代器是这样的对象:实现了无参数的 next 方法,返回下一个元素,如果没有元素了,那么抛出 StopIteration 异常;并且实现iter 方法,返回迭代器本身。

(3)什么是生成器? 生成器是带有 yield 关键字的函数。调用生成器函数时,会返回一个生成器对象。

(4)什么是生成器表达式? 生成器表达式是创建生成器的简洁句法,这样无需先定义函数再调用。

(0)

相关推荐

  • Python学习之迭代器和生成器有什么不同?

    迭代器和生成器区别是什么?相信很多人在初学Python的时候对它们都很好奇,接下来我们一起来看看它们的区别吧. 迭代器是一个更抽象的概念,任何对象,如果它的类有next方法和iter方法返回自己的本身 ...

  • Python基础篇--迭代器,生成器和装饰器

    迭代 遵循迭代器协议时,需要Python迭代器对象支持两种方法. __iter__返回迭代器对象本身.这用于for 和in语句. __next__方法从迭代器返回下一个值.如果没有其他项目要返回,则应 ...

  • 面试题-python 什么是迭代器?

    前言 python 里面有 3 大神器:迭代器,生成器,装饰器.在了解迭代器之前,需弄清楚2个概念: 1.什么是迭代 2.什么是可迭代对象 迭代 如果给定一个list或tuple,我们可以通过for循 ...

  • 总算搞明白了!进程,线程,协程,生成器,迭代器搞的我脑子好乱!

    你是否曾经被迭代器,生成器,进程,线程,协程搞的脑子很乱? 而且剪不断,理还乱: 这不怪你,这是有历史原因.本文试图把东西都给理顺了. 一篇不行,咱们就再来一篇,使劲点赞. 两个问题,三种协程 先来看 ...

  • Python迭代器

    迭代器是可以迭代的对象. 在本教程中,您将了解迭代器的工作原理,以及如何使用__iter__和__next__方法构建自己的迭代器. 迭代器在Python中无处不在. 它们优雅地实现在循环,推导,生成 ...

  • 一文掌握 Python 迭代器的原理

    理解迭代器是每个严肃的 Python 使用者学习 Python 道路上的里程碑.本文将从零开始,一步一步带你认识 Python 中基于类的迭代器. 相较于其他编程语言,Python 的语法是优美而清晰 ...

  • 【Python 第75课】可迭代对象和迭代器

    for 循环是我们在 Python 里非常常用的一个语法,但你有没有思考过 for 循环是怎样实现的? 如果你以前接触过 C++,应该会知道类似 for (int i = 0; i < 100; ...

  • 一文读懂Python中的异常处理

    异常处理语句 try...excpet...finally 实例代码 def div(a, b):    try:        print(a / b)    except ZeroDivision ...

  • 【进阶】一文读懂Python装饰器,搞清来龙去脉!

    (给机器学习算法与Python学习加星标,提升AI技能) 选自pouannes.github.io 作者:Pierre Ouannes 本文由机器之心(nearhuman2014)翻译 原文:http ...

  • 【Python】一文读懂Python正则表达式常用用法

    重磅干货,第一时间送达 编辑:爱学AI 来源:geekvi   链接: www.segmentfault.com/a/1190000007929344 简介 正则表达式(regular express ...

  • 一文读懂 Python web 框架和 web 服务器之间的关系

    (给Python开发者加星标,提升Python技能) 来源:  Python编程与实战-Jerryning [导读]:如果面试的时候问你:一个请求从浏览器发出到数据返回都经历过哪些过程?能否准确的回答 ...

  • 一文读懂如何提升Abaqus Python二次开发代码通用性

    来源:复合材料力学 作者:君莫 我们在Abaqus/CAE中进行各种操作时,后台的各种指令会实时记录在rpy文件和jnl文件中,因此,在Abaqus二次开发中,为了提升编程效率,经常需要调取rpy文件 ...

  • 一文读懂 Redis 常见对象类型的底层数据结构

    (给数据分析与开发加星标,提升数据技能) 转自:伍陆七, 链接:cnblogs.com/chentianming/p/13838347.htm Redis 是一个基于内存中的数据结构存储系统,可以用作 ...

  • 一文读懂王清任的五逐瘀汤

    至道汇 今天 瘀血 王清任三步辨瘀血法及其临床应用 一.首辨瘀血典型症状的有无 无论瘀血为病,证候有多么复杂多变,其外在表现总会有一定规律可循.其中表现突出且有别于他证的特异性症状,便可视为瘀血的典型 ...

  • 一文读懂硬度试验

    硬度,硬度测量,硬度公式,硬度换算,材料硬度,钢材硬度,布氏硬度,硬度试验 来源:北京赛亿科技有限公司

  • 一文读懂:广东人从哪里来?

    岭南韵味  广府情怀 粤曲| 粤剧 | 名家 | 名段 很多外省的朋友们不是很了解广东人的组成及来源,也不知道为何叫做"广东".更会有一些朋友会奇怪: ◆为什么秦汉时期的" ...