• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >python > Python函数式编程指南(三):迭代器详解

Python函数式编程指南(三):迭代器详解

作者: 字体:[增加 减小] 来源:互联网

通过本文主要向大家介绍了python函数式编程,函数式编程,函数式编程语言,javascript函数式编程,js函数式编程等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

3. 迭代器

3.1. 迭代器(Iterator)概述

迭代器是访问集合内元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束。

迭代器不能回退,只能往前进行迭代。这并不是什么很大的缺点,因为人们几乎不需要在迭代途中进行回退操作。

迭代器也不是线程安全的,在多线程环境中对可变集合使用迭代器是一个危险的操作。但如果小心谨慎,或者干脆贯彻函数式思想坚持使用不可变的集合,那这也不是什么大问题。

对于原生支持随机访问的数据结构(如tuple、list),迭代器和经典for循环的索引访问相比并无优势,反而丢失了索引值(可以使用内建函数enumerate()找回这个索引值,这是后话)。但对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式。

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

迭代器更大的功劳是提供了一个统一的访问集合的接口。只要是实现了__iter__()方法的对象,就可以使用迭代器进行访问。

3.2. 使用迭代器

使用内建的工厂函数iter(iterable)可以获取迭代器对象:
>>> lst = range(2)
>>> it = iter(lst)
>>> it
<listiterator object at 0x00BB62F0>
</div>
使用迭代器的next()方法可以访问下一个元素:
>>> it.next()
0
</div>
如果是Python 2.6+,还有内建函数next(iterator)可以完成这一功能:
>>> next(it)
1
</div>
如何判断迭代器还有更多的元素可以访问呢?Python里的迭代器并没有提供类似has_next()这样的方法。
那么在这个例子中,我们已经访问到了最后一个元素1,再使用next()方法会怎样呢?
>>> it.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
</div>

Python遇到这样的情况时将会抛出StopIteration异常。事实上,Python正是根据是否检查到这个异常来决定是否停止迭代的。
这种做法与迭代前手动检查是否越界相比各有优点。但Python的做法总有一些利用异常进行流程控制的嫌疑。

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

it = iter(lst)
try:
    while True:
        val = it.next()
        print val
except StopIteration:
    pass
</div>

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

for val in lst:
    print val
</div>

首先Python将对关键字in后的对象调用iter函数获取迭代器,然后调用迭代器的next方法获取元素,直到抛出StopIteration异常。对迭代器调用iter函数时将返回迭代器自身,所以迭代器也可以用于for语句中,不需要特殊处理。

常用的几个内建数据结构tuple、list、set、dict都支持迭代器,字符串也可以使用迭代操作。你也可以自己实现一个迭代器,如上所述,只需要在类的__iter__方法中返回一个对象,这个对象拥有一个next()方法,这个方法能在恰当的时候抛出StopIteration异常即可。但是需要自己实现迭代器的时候不多,即使需要,使用生成器会更轻松。下一篇我们将讨论生成器的部分。

*异常并不是非抛出不可的,不抛出该异常的迭代器将进行无限迭代,某些情况下这样的迭代器很有用。这种情况下,你需要自己判断元素并中止,否则就死循环了!

使用迭代器的循环可以避开索引,但有时候我们还是需要索引来进行一些操作的。这时候内建函数enumerate就派上用场咯,它能在iter函数的结果前加上索引,以元组返回,用起来就像这样:
for idx, ele in enumerate(lst):
    print idx, ele
</div>

3.3. 生成器表达式(Generator expression)和列表解析(List Comprehension)
绝大多数情况下,遍历一个集合都是为了对元素应用某个动作或是进行筛选。如果看过本文的第二部分,你应该还记得有内建函数map和filter提供了这些功能,但Python仍然为这些操作提供了语言级的支持。

(x+1 for x in lst) #生成器表达式,返回迭代器。外部的括号可在用于参数时省略。
[x+1 for x in lst] #列表解析,返回list
</div>

如你所见,生成器表达式和列表解析(注:这里的翻译有很多种,比如列表展开、列表推导等等,指的是同一个意思)的区别很小,所以人们提到这个特性时,简单起见往往只描述成列表解析。然而由于返回迭代器时,并不是在一开始就计算所有的元素,这样能得到更多的灵活性并且可以避开很多不必要的计算,所以除非你明确希望返回列表,否则应该始终使用生成器表达式。接下来的文字里我就不区分这两种形式了:)

你也可以为列表解析提供if子句进行筛选:

(x+1 for x in lst if x!=0)
</div>
或者提供多条for子句进行嵌套循环,嵌套次序就是for子句的顺序:

((x, y) for x in range(3) for y in range(x))
</div>

列表解析就是鲜明的Pythonic。我常遇到两个使用列表解析的问题,本应归属于最佳实践,但这两个问题非常典型,所以不妨在这里提一下:

第一个问题是,因为对元素应用的动作太复杂,不能用一个表达式写出来,所以不使用列表解析。这是典型的思想没有转变的例子,如果我们将动作封装成函数,那不就是一个表达式了么?

第二个问题是,因为if子句里的条件需要计算,同时结果也需要进行同样的计算,不希望计算两遍,就像这样:

(x.doSomething() for x in lst if x.doSomething()>0)
</div>

这样写确实很糟糕,但组合一下列表解析即可解决:

您可能想查找下面的文章:

  • 总结Python编程中函数的使用要点
  • Python函数式编程指南(四):生成器详解
  • Python函数式编程指南(三):迭代器详解
  • Python函数式编程指南(二):从函数开始
  • Python函数式编程指南(一):函数式编程概述
  • 利用Fn.py库在Python中进行函数式编程
  • 用Python进行基础的函数式编程的教程
  • Python装饰器的函数式编程详解

相关文章

  • No connection adapters were found
  • 详尽讲述用Python的Django框架测试驱动开发的教程
  • Python3连接MySQL(pymysql)模拟转账实现代码
  • 基于python编写的微博应用
  • Python的Bottle框架中实现最基本的get和post的方法的教程
  • Python两个内置函数 locals 和globals(学习笔记)
  • python类和继承用法实例
  • pyramid配置session的方法教程
  • windows10系统中安装python3.x+scrapy教程
  • Python简单计算文件夹大小的方法

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • python读取csv文件示例(python操作csv)
    • Python实现以时间换空间的缓存替换算法
    • python重试装饰器示例
    • 详解python的数字类型变量与其方法
    • Python break语句详解
    • Python中使用HTMLParser解析html实例
    • 解读Python中degrees()方法的使用
    • python类继承用法实例分析
    • bpython 功能强大的Python shell
    • python实现bitmap数据结构详解

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有