英文原文出处: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. Python--urllib3库

    Urllib3是一个功能强大,条理清晰,用于HTTP客户端的Python库,许多Python的原生系统已经开始使用urllib3.Urllib3提供了很多python标准库里所没有的重要特性:   1 ...

  2. Navicat for MySQL使用手记(下)--实现自动备份数据库

    五.备份和还原MySQL数据库 在数据库的管理中,备份和还原是必须做认真做的事情,如果疏忽或者做粗糙了,那么一旦数据库故障后果不堪设想,所以Navicat同样也有备份和还原的功能,相比较创建功能,其备 ...

  3. Eclipse 模拟http 请求插件Rest Client

    eclipse update 网址  http://nextinterfaces.com/http4e/install/ 参考 http://www.nextinterfaces.com/eclips ...

  4. unittest--unittest.defaultTestLoader()的方法

    unittest.defaultTestLoader(): defaultTestLoader()类,通过该类下面的discover()方法可自动更具测试目录start_dir匹配查找测试用例文件(t ...

  5. java图形用户界面添加背景颜色不成功的解决方案

    总结:背景颜色不成功,那么使用这个方法试试.getContentpane(); package clientFrame; import java.awt.Color; import java.awt. ...

  6. Laravel5 cookie和session设置 Cookie::queue()自动添加

    Cookies Laravel会加密所有已创建的cookie信息,并附加上授权码,当客户端擅自修改cookie信息时,该cookie将被废弃,从而保证安全性. 获取一个指定的cookie值 $valu ...

  7. verilog HDL 编码风格

    1.有意义且有效的名字. 2.同一信号在不同层次应该保持一致. 3.添加有意义的后缀,使信号的有效性更加明确. 4.模块输出寄存器化,使得输出的驱动强度和输入延时是可以预测的. 5.使用括号表明优先级 ...

  8. ASP.NET页面传值加号变空格解决办法

    只需要把欲传值进行编码 string EncodeId = Server.UrlEncode(id); 加号就变成了 % 2 B  (中间无空格) 然后再传出去. Request.QueryStrin ...

  9. ARM六种寻址方式的汇编实现

    AREA Example,CODE,READONLY ENTRY CODE32 ;S 后缀:更新标志位CPSR ;!后缀:基址寄存器中的地址发生变化 ;LDR 从存储器中加载数据到寄存器 ;STR 从 ...

  10. HTML_基础篇

    一.HTML的概述 什么是HTML? html:Hyper Test Markup Language 超文本标记语言(它不是编程语言!) 超文本:功能比普通的文本更加强大. 标记语言:使用一组标签对内 ...