英文原文出处: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. unittest之跳过用例(skip) (含如何调用类里面函数相互调取变量的方法)

    当测试用例写完后,有些模块有改动时候,会影响到部分用例的执行,这个时候我们希望暂时跳过这些用例. 或者前面某个功能运行失败了,后面的几个用例是依赖于这个功能的用例,如果第一步就失败了,后面的用例也就没 ...

  2. java数组求输入平均值

    真是学了后面忘了前面,一维数组都忘了 package com.c2; //总结类型转换不对,导致运行报错 //以及没有new,导致空指针异常 //引入流. import java.io.*; publ ...

  3. 杂项:UN-HTML

    ylbtech-杂项:HTML 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返回顶部   8.返回顶部   9.返回顶部   1 ...

  4. 理解contextmanager

    同事在查看网络问题导致虚拟机状态一直pause时,在一段代码(见以下)处产生了疑惑.问我,我也是一头雾水.后同事找到参考文章(1),算是了解了个大概.而我对contextmanager的工作产生了兴趣 ...

  5. C语言中的未初始化变量的值

    C语言中未初始化的变量的值是0么 全局变量 .静态变量初始值为0局部变量,自动变量初始值随机分配 C语言中,定义局部变量时如果未初始化,则值是随机的,为什么? 定义局部变量,其实就是在栈中通过移动栈指 ...

  6. 如何卸载win10的自带应用

    win10自带了好多应用,有些看起来不错,其实用起来不太方便哈(我的个人感觉),我们都更喜欢第三方应用,所以我们就来看看如何卸载这些自带应用.如图,是卸载完成后的Windows PowerShell: ...

  7. sql代码段添加数据

      declare @i int,@index int     set @i=1     set @index=0   while @i<1000000   begin    set @inde ...

  8. Enumeration & Structures & Protocl & Extension

    [Enumeration and Structures] 1.使用toRaw.fromRaw方法可以在原始值之间.注意enum的定义中使用了case.另外要注意switch中的枚举值. 2.struc ...

  9. node.js中模块报错【window is not defined】的解决方法

    (function(window) { /* Keep source code the same */ // })(typeof window == "undefined" ? g ...

  10. C# 堆和栈的区别?

    解释1.栈是编译期间就分配好的内存空间,因此你的代码中必须就栈的大小有明确的定义:堆是程序运行期间动态分配的内存空间,你可以根据程序的运行情况确定要分配的堆内存的大小 解释2. 存放在栈中时要管存储顺 ...