在 python 中我们常用 for in 来遍历 list, set, dict, str 等。

for in 的本质就干了两件事:

  1. 调用 _iter_() 获取迭代器;
  2. 调用 next() 直到 StopIteration 异常; (python3 中是 _next_())

迭代器

我们先了解几个概念:

  • Iterable: 可迭代对象
  • Iterator: 迭代器

我们先看看 Iterable 的实现

from collections import Iterable

help(Iterable)

class Iterable(__builtin__.object)
| Methods defined here:
|
| __iter__(self)
|
| ----------------------------------------------------------------------
| Class methods defined here:
|
| __subclasshook__(cls, C) from abc.ABCMeta
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| __abstractmethods__ = frozenset(['__iter__'])
|
| __metaclass__ = <class 'abc.ABCMeta'>
| Metaclass for defining Abstract Base Classes (ABCs).
|
| Use this metaclass to create an ABC. An ABC can be subclassed
| directly, and then acts as a mix-in class. You can also register
| unrelated concrete classes (even built-in classes) and unrelated
| ABCs as 'virtual subclasses' -- these and their descendants will

再看看 Iterator 的实现

from collections import Iterator

help(Iterator)

class Iterator(Iterable)
| Method resolution order:
| Iterator
| Iterable
| __builtin__.object
|
| Methods defined here:
|
| __iter__(self)
|
| next(self)
| Return the next item from the iterator. When exhausted, raise StopIteration
|
| ----------------------------------------------------------------------
| Class methods defined here:
|
| __subclasshook__(cls, C) from abc.ABCMeta
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| __abstractmethods__ = frozenset(['next'])
|
| ----------------------------------------------------------------------
| Data descriptors inherited from Iterable:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and other attributes inherited from Iterable:
|
| __metaclass__ = <class 'abc.ABCMeta'>
| Metaclass for defining Abstract Base Classes (ABCs).
|
| Use this metaclass to create an ABC. An ABC can be subclassed
| directly, and then acts as a mix-in class. You can also register
| unrelated concrete classes (even built-in classes) and unrelated
| ABCs as 'virtual subclasses' -- these and their descendants will
| be considered subclasses of the registering ABC by the built-in
| issubclass() function, but the registering ABC won't show up in
| their MRO (Method Resolution Order) nor will method
| implementations defined by the registering ABC be callable (not
| even via super()).

从继承关系来看,所有的 Iterator(迭代器)都是 Iterable(可迭代对象),

从实现角度看 Iterator 新增了 next() 方法。

判断是 Iterator 还是 Iterable

  • 凡是可以 for 循环的,都是 Iterable;
  • 凡是可以 next() 的,都是 Iterator;
  • list, tuple, dict, str, set 都不是 Iterator,但是可以通过 _iter_() 返回一个 Iterator 对象
from collections import Iterator, Iterable

isinstance([1,], Iterator)    // False
isinstance((1,), Iterator) // False
isinstance({}, Iterator) // False
isinstance("abc", Iterator) // False
isinstance(set([]), Iterator) // False isinstance([1,], Iterable) // True
isinstance((1,), Iterable) // True
isinstance({}, Iterable) // True
isinstance("abc", Iterable) // True
isinstance(set([]), Iterable) // True dir([]) // 没有 next() 方法
dir([].__iter__()) // 有 next() 方法

生成器

将完了迭代器,我们再说说生成器,这里引用廖雪峰博客里的介绍:

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。

而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,

如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?

这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,

称为生成器(Generator)。

生成器的创建很简单,可以通过推导列表创建:

 g = (x * x for x in range(10))  // 使用 [] 返回的是 list, () 返回的是 generator

还有一种方式是通过 yield 关键字生成。

先看看生成器的实现:

<genexpr> = class generator(object)
| Methods defined here:
|
| __getattribute__(...)
| x.__getattribute__('name') <==> x.name
|
| __iter__(...)
| x.__iter__() <==> iter(x)
|
| __repr__(...)
| x.__repr__() <==> repr(x)
|
| close(...)
| close() -> raise GeneratorExit inside generator.
|
| next(...)
| x.next() -> the next value, or raise StopIteration
|
| send(...)
| send(arg) -> send 'arg' into generator,
| return next yielded value or raise StopIteration.
|
| throw(...)
| throw(typ[,val[,tb]]) -> raise exception in generator,
| return next yielded value or raise StopIteration.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| gi_code
|
| gi_frame
|
| gi_running

可以发现生成器较迭代器多了 send, throw 等方法。

send

这里重点介绍下 send 方法,我们知道在使用迭代器时,遇到 yield 关键字

会退出来,下一迭代时会继续执行。先看个例子:

def MyGenerator():
value = yield 1
value = yield value gen = MyGenerator()
print gen.next() // print 1
print gen.next() // print None

我们看看具体执行过程:

  • 调用 next() 方法,走到 yield 1 退出,注意这个时候还没有走到 value 的 赋值操作(即: value = yield 1 只执行了右侧部分)
  • 调用 next() 方法,继续上次的代码执行(即:value = yield 1 只执行了右侧的赋值部分)
  • 由于 yield 并没有返回值,所以 value = None
  • 返回 None, 并打印

修改下上面的例子:

def MyGenerator():
value = yield 1
value = yield value gen = MyGenerator()
print gen.next() // print 1
print gen.send(2) // print 2

send 方法是指定的是上一次被挂起的yield语句的返回值,这么说有点抽象,我们看执行过程:

  • 调用 next() 方法,走到 yield 1 退出,注意这个时候还没有走到 value 的 赋值操作(即: value = yield 1 只执行了右侧部分)
  • 调用 send(2) 方法,继续上次的代码执行(即:value = yield 1 只执行了右侧的赋值部分)
  • value 使用 send 传的值,即: value = 2
  • 返回 2, 并打印

协程

协程就是利用 yield 和生成器的 send() 方法实现的。

python 迭代器,生成器的更多相关文章

  1. Python迭代器生成器与生成式

    Python迭代器生成器与生成式 什么是迭代 迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果.每一次对过程的重复称为一次"迭代",而每一次迭代得到的结果会作为下一次迭 ...

  2. Python 迭代器&生成器

    1.内置参数     Built-in Functions     abs() dict() help() min() setattr() all() dir() hex() next() slice ...

  3. python 迭代器 生成器

    迭代器 生成器 一 什么是迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前 ...

  4. Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发

    本节大纲 迭代器&生成器 装饰器  基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...

  5. python迭代器,生成器,推导式

    可迭代对象 字面意思分析:可以重复的迭代的实实在在的东西. list,dict(keys(),values(),items()),tuple,str,set,range, 文件句柄(待定) 专业角度: ...

  6. 4.python迭代器生成器装饰器

    容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元素存储在内存中 ...

  7. python迭代器生成器

    1.生成器和迭代器.含有yield的特殊函数为生成器.可以被for循环的称之为可以迭代的.而可以通过_next()_调用,并且可以不断返回值的称之为迭代器 2.yield简单的生成器 #迭代器简单的使 ...

  8. Python迭代器生成器,私有变量及列表字典集合推导式(二)

    1 python自省机制 这个是python一大特性,自省就是面向对象的语言所写的程序在运行时,能知道对象的类型,换句话说就是在运行时能获取对象的类型,比如通过 type(),dir(),getatt ...

  9. Python迭代器生成器,模块和包

      1.迭代器和生成器 2.模块和包 1.迭代器 迭代器对象要求支持迭代器协议的对象,在Python中,支持迭代器协议就是实现对象的__iter__()和__next__()方法.    其中__it ...

  10. python迭代器生成器-迭代器和list区别

    迭代 生成 for循环遍历的原理 for循环遍历的原理就是迭代,in后面必须是可迭代对象 为什么要有迭代器 对于序列类型:字符串.列表.元组,我们可以使用索引的方式迭代取出其包含的元素.但对于字典.集 ...

随机推荐

  1. HTTP深入浅出 http请求完整过程

    HTTP(HyperText Transfer Protocol)是一套计算机通过网络进行通信的规则.计算机专家设计出HTTP,使HTTP客户(如Web浏览器)能够从HTTP服务器(Web服务器)请求 ...

  2. Linux CentOS7 安装wkhtmltopdf工具

    wkhtmltopdf是一款将html文件转换成pdf格式的优秀的文件内容转换工具.它使用QT作为渲染引擎,目前它的RELEASE版尚不支持flex布局的Html5代码转换.使用flex的嵌套元素将会 ...

  3. HDU-1398 Square Coins(生成函数)

    题意 与$hdu1028$类似,只不过可用的数字都是平方数. 思路 类似的思路,注意下细节. 代码 #include <bits/stdc++.h> #define DBG(x) cerr ...

  4. linux服务器磁盘挂载操作

    具体操作是:先对磁盘进行格式化,格式化后挂载到需要的挂载点,最后添加分区启动表,以便下次系统启动随机自动挂载.1.首先查看系统中磁盘信息,命令为:fdisk -l; 2.找到未使用的磁盘,对其进行格式 ...

  5. “短路求值(Short-Circuit Evaluation)

        // 逻辑与和逻辑或操作符总是先计算其做操作数,只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解其右操作数. function aa() { if (null) { console ...

  6. 服务器 隐藏php版本,nginx版本号等

    隐藏php版本号: 打开php.ini配置文件  找到 expose_php 关键修改为 off 即可 重启后 web头部就不会有了 隐藏 nginx 服务器版本号: 打开nginx配置文件,在htt ...

  7. android TextView加载html 过滤所有标签,保留换行标签

    情景: TextView加载后端接口获取到的html富文本 遇到的问题: 客户端通过接口取到的数据如下: <p style="margin-top: 0px; margin-botto ...

  8. VGA、DVI、HDMI三种视频信号接口

    目前,电脑显示器常见的接口主要有HDMI.DP.DVI.VGA等4种接口.显示器数据线性能排名:DP>HDMI>DVI>VGA.其中 
VGA是模拟信号,已经被主流所淘汰,DVI.H ...

  9. MailKit系列之附件分离

    本文主要谈谈实现思路,不提供完整代码 一.分离基础 1.MIME邮件的multipart类型 引用文章:https://blog.csdn.net/wangyu13476969128/article/ ...

  10. 【转】iPython入门技巧

    [转]http://www.cnblogs.com/cuiyubo/p/6823478.html 学习<利用python进行数据分析> 第三章 IPython:一种交互式计算和开发环境的笔 ...