英文原文出处:Use More Iterators

本文介绍将代码转换为使用迭代器的原因和实用技巧。

我最喜欢的Python语言的特色之一是生成器,它们是非常有用的,然而当阅读开源代码时,我很少遇到它们。在这篇文章中,我希望概述它们最简单的实例去鼓励任何读者更多的使用它们。

阅读这篇文章的前提是你已经知道容器和迭代器是什么,我在之前的一篇博客文章中已经解释过这些概念,并详细阐述了我们通过更多的一些思考能获得什么。

Why?

为什么使用迭代器是一个好的方法?使用迭代器编程能避免使用中间变量,可以用更短的代码,运行轻松,消耗更小的内存,运行更快,组合性强,也更加漂亮。简而言之:它们更加优雅。

"The moment you've made something iterable, you've done something magic with your code. As soon as something's iterable, you can feed it to list(), set(), sorted(), min(), max(), heapify(), sum(), ‥. Many of the tools in Python consume iterators."

“当你做了一些可迭代的事情, 你已经为你的代码做了一些魔术。一旦它变得可迭代,你就能使用ist(), set(), sorted(), min(), max(), heapify(), sum()等函数,Python中的很多工具都使用迭代器。”

— Raymond Hettinger ([Transfroming Code into Beautiful, Idiomatic Python](https://www.youtube.com/watch?v=OSGv2VnC0go#t=825))

最近, Clojure为编程语言加了transducer, 这是一个与Python中的生成器非常相似的概念。(我强烈建议观看Rich Hickey 2014年在介绍它时在Strange Loop 的演讲:"Transduers" by Rich Hicky。)

在视频中, 他谈到把一个集合"puring"到另一个, 我认为这是一个动词, 非常直观地描述迭代器的性质与数据结构的关系。我将在未来的博客文章中更详细地写下这个想法。

Example

下面是一个常见的示例:

def get_lines(f):
result = []
for line in f:
if not line.startswith('#'):
result.append(line)
return result lines = get_lines(f)

现在看看用生成器写同样功能的代码:

def get_lines(f):
for line in f:
if not line.startswith('#'):
yield line lines = list(get_lines(f))

The Benefits

咋一看似乎没有太多不同之处,但是却有很多好处:

  • No bookkeeping(没有记录本). 你不需要创建一个空列表,然后一个个添加元素到里面,并返回它,这就少使用了一个变量;
  • Hardly consumes memory(几乎不耗内存). 无论输入文件有多大, 含迭代器的代码都不需要在内存中缓冲整个文件;
  • Works with infinite streams(可工作在无限流状态下).
  • Faster results(返回值更快). 可以立即得到返回结果, 而不是在读取整个文件之后;
  • Faster speed(运行速度更快). 第二段代码相比于第一段代码需要以初始方式创建列表运行的更快;
  • Composability(可组合性). 调用方式可以决定它如何使用返回结果。

最后一点也是最重要的,让我们深究它。

Composability

可组合性是关键之处。迭代器有着极强的组合性,在上面的例子中,列表是显性的创建,但是如果调用者需要一个集合呢?实际上,许多人要么写一个同样功能的基于集合的代码段,或者简单的调用函数set(),当然这是可行的,但是这非常浪费内存资源。再次想象一下这个文件很大,首先从这整个文件已经生成了一个很大的列表list,然后又使用set()通过这个列表在内存中生成一个所需要的集合set,那么原先的中间变量列表就是内存中的垃圾。

而对于使用生成器,函数只是发出“对象流”,调用者再决定将这些对象使用(puring)到什么数据类型中。

想要生成集合而不是列表?

uniq_lines = set(get_lines(f))

只想要文件中最长的一行吗?该文件将被完全读取, 但最多两行始终保存在内存中:

longest_line = max(get_lines(f), key=len)

只想要文件中的前10行吗?将从文件中读取不超过10行, 无论文件有多大:

head = list(islice(get_lines(f), 0, 10))

2013年在Pycon,Ned Batchelder 的演讲非常完美的阐述了我在这篇博文中所尝试解释的,我强烈推荐你们观看:Loop like a native: while, for, iterators, generators.

Summary

不要让中间变量在内存中存储数据,你几乎总是可以避开它们, 那么就可以获得可读性、速度、更小的内存占用空间和可组合性的回报。

< 完 >

转载请注明该译文原文链接: < https://www.cnblogs.com/tzhao/p/9874135.html >,谢谢!

Python中多使用迭代器的更多相关文章

  1. Python中生成器和迭代器的区别(代码在Python3.5下测试):

    https://blog.csdn.net/u014745194/article/details/70176117 Python中生成器和迭代器的区别(代码在Python3.5下测试):Num01–& ...

  2. python中“生成器”、“迭代器”、“闭包”、“装饰器”的深入理解

    python中"生成器"."迭代器"."闭包"."装饰器"的深入理解 一.生成器 1.生成器定义:在python中,一边 ...

  3. python中“生成器”、“迭代器”、“闭包”、“装饰器”的深入理解

    一.生成器 1.什么是生成器? 在python中,一边循环一边计算的机制,称为生成器:generator. 2.生成器有什么优点? 1.节约内存.python在使用生成器时对延迟操作提供了支持.所谓延 ...

  4. python中生成器及迭代器

    列表生成式 列表生成式是python内部用来创建list的一种方法,其格式形如: L = [x*8 for x in range(10)] print(L) 此时会得到结果:[0, 8, 16, 24 ...

  5. Python中生成器和迭代器的功能介绍

    生成器和迭代器的功能介绍 1. 生成器(generator) 1. 赋值生成器 1. 创建 方法:x = (variable for variable in iterable) 例如:x = (i f ...

  6. python中生成器与迭代器

    可迭代对象:一个实现了iter方法的对象是可迭代的 迭代器:一个实现了iter方法和next方法的对象就是迭代器 生成器都是Iterator对象,但list.dict.str虽然是Iterable(可 ...

  7. Python高级特性:迭代器和生成器

    在Python中,很多对象都是可以通过for语句来直接遍历的,例如list.string.dict等等,这些对象都可以被称为可迭代对象.至于说哪些对象是可以被迭代访问的,就要了解一下迭代器相关的知识了 ...

  8. Python高级特性:迭代器和生成器 -转

    在Python中,很多对象都是可以通过for语句来直接遍历的,例如list.string.dict等等,这些对象都可以被称为可迭代对象.至于说哪些对象是可以被迭代访问的,就要了解一下迭代器相关的知识了 ...

  9. Python中的迭代器和生成器

    本文以实例详解了python的迭代器与生成器,具体如下所示: 1. 迭代器概述: 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后 ...

随机推荐

  1. FPGA中计数器设计探索

    FPGA中计数器设计探索,以计数器为32位为例: 第一种方式,直接定义32位计数器. reg [31:0]count; quartus ii 下的编译,资源消耗情况. 85C模型下的时钟频率. 0C模 ...

  2. mysql索引之二:数据结构及算法原理

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

  3. juc线程池原理(二):ThreadPoolExecutor的成员变量介绍

    概要 线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析ThreadPoolExecutor类,来了解线程池的原理. ThreadPoolExecutor数据结构 Thread ...

  4. 1134 Vertex Cover

    题意:给出一个图和k个查询,每个查询给出Nv个结点,问与这些结点相关的边是否包含了整个图的所有边. 思路:首先,因为结点数较多,用邻接表存储图,并用unordered_map<int,unord ...

  5. Composer安装使用

    Composer 是 PHP5.3以上 的一个依赖管理工具.它允许你申明项目所依赖的代码库,它会在你的项目中为你安装他们. 1.下载 2.安装成功 3.配置地址 4.安装代码库 镜像 配置json

  6. 编写一个jQuery的扩展方法(插件)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. Python Twisted架构英文版

    原作出处:twisted-intro 作者:Dave 转载声明:版权归原作出处所有,转载只为让更多人看到这部优秀作品合集,如果侵权,请留言告知 Twisted Introduction This mu ...

  8. oracle数据库中函数的递归调用

    如有下面的表结构AAAA,用一个字段prev_id表示记录的先后顺序,要对其排序,需要用的递归函数 ID PREV_ID CONT 99   a 23 54 d 21 23 e 54 33 c 33 ...

  9. 前端学习---css基本知识

    css基本知识 我们先看一个小例子: <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  10. Java微信公众平台开发(三)--接收消息的分类及实体的创建

    转自:http://www.cuiyongzhi.com/post/41.html 前面一篇有说道应用服务器和腾讯服务器是通过消息进行通讯的,并简单介绍了微信端post的消息类型,这里我们将建立消息实 ...