python中的generator, iterator, iterabel
先来看看如果遇到一个对象,如何判断其是否是这三种类型:
from types import GeneratorType
from collectiuons import Iterable, Iterator isinstance( xx, GeneratorType )
isinstance( xx, Iterable )
isinstance( xx, Iterator )
生成器对象:
生成器是一个通过yield关键字构建的函数,其返回一个generator对象,同时其又是一个iterator对象,因为其实现了__iter__与next方法
In[4]: def gene(k):
... for i in xrange(0, k):
... yield i
...
In[5]: ge = gene(6)
In[6]: type(ge)
Out[6]: generator
In[8]: dir(ge)
Out[8]: [ ...,'__iter__', 'next', ... ]
In[9]: isinstance(ge, collections.Iterator)
Out[9]: True
生成器的一个特点是只能用一次
In[11]: for i in ge:
... print i
...
0
1
2
3
4
5
In[12]: ge.next()
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/IPython/core/interactiveshell.py", line 2820, in run_code
exec code_obj in self.user_global_ns, self.user_ns
File "<ipython-input-12-b9172cd6050f>", line 1, in <module>
ge.next()
StopIteration
迭代器对象:
实现了__iter__与__next__方法的对象。
__iter__返回一个实例作为最终使用的iterator对象--for...in...语句初始化时使用,next方法是后面每次迭代iterator对象时调用的方法
class Counter(object):
def __init__(self, low, high):
self.current = low
self.high = high def __iter__(self):
# 'Returns itself as an iterator object'
return self def next(self):
# 'Returns the next value till current is lower than high'
if self.current > self.high:
raise StopIteration
else:
self.current += 1
return self.current - 1
>>> c = Counter(5,10)
>>> for i in c:
... print(i, end=' ')
...
5 6 7 8 9 10
>>> for i in c:
... pritn i
...
# 无输出
>>> c.next()
Traceback (most recent call last):
File "<ipython-input-12-b9172cd6050f>"
c.next()
StopIteration
可迭代对象:
可迭代对象就是用于for...in...循环的
不同于上面两种,其需要可以多次for...in...使用
通过generator写可迭代对象:
将__iter__写成生成器函数。注意for...in...时初始化时调用__iter__函数使得counter为low, 而后执行的都是yield所影响区域的了【1】,除非下次再执行for...in...语句才会调用到counter初始化那句,这样也就实现了复用。但是有个问题是此时Counter的实例就既不是generator也不是iterator对象了。故其也没法调用next方法
class Counter(object):
def __init__(self, low, high):
self.low = low
self.high = high def __iter__(self):
counter = self.low
while self.high >= counter:
yield counter
counter += 1 obj = Counter(5, 10)
print isinstance(obj, Iterator)
print isinstance(obj, GeneratorType)
print type(obj)
for i in obj:
print i
obj.next()
False
False
<class '__main__.Counter'>
5
6
7
8
9
10
Traceback (most recent call last):
File "/home/pd/..."
obj.next()
AttributeError: 'Counter' object has no attribute 'next'
注释【1】:
In [1]: def gener(k):
...: print "====initial===="
...: for i in range(0, k):
...: print "before yield"
...: yield i
...: print "after yield"
...: print "*****end******"
...: In [2]: g = gener(3)
In [3]: for i in g:
...: print g
...:
====initial====
before yield
<generator object gener at 0x7fbc8d15e870>
after yield
before yield
<generator object gener at 0x7fbc8d15e870>
after yield
before yield
<generator object gener at 0x7fbc8d15e870>
after yield
*****end******
补充:
关于generator的yield与send:
总的来说:yield返回的是个generator对象,send是向generator输送值
In [35]: def gen():
...: while True:
...: print("before x_yield")
...: x=yield
...: print("after x_yield:", x)
...: yield x*2
...: print("after yield")
...:
...: In [36]: g = gen() In [37]: g.send(10)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-37-98b613a2ec82> in <module>()
----> 1 g.send(10) TypeError: can't send non-None value to a just-started generator In [38]: g.__next__(10)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-38-bc5eb41f1cb6> in <module>()
----> 1 g.__next__(10) TypeError: expected 0 arguments, got 1 In [39]: g.__next__()
before x_yield
# 由上可知, “x=yield”中的yield也会成为__next__()调用的终点,也就是说如果上面要两个__next__()才能走完。
31 # 通过实验发现,其实x=yield的执行并不是同时的,比如send(10),此时相当于到达了x=yield中的yield,而此时再执行send(11)才会执行x=yield这个赋值操作
31 # 所以输出是22而不是第一次就能传入的20【见43,44的输出】 In [40]: g.send(10)
after x_yield: 10
Out[40]: 20 # 进行到yield x*2 In [41]: g.__next__()
after yield
before x_yield In [42]: g.send(10)
after x_yield: 10
Out[42]: 20 In [43]: g.send(10) #
after yield
before x_yield In [44]: g.send(11)
after x_yield: 11
Out[44]: 22
补充:关于send与__next__()
In [71]: def gen():
...: print("enhen")
...: while True:
...: print("before yield")
...: yield "pd the handsome"
...: print("afer yield")
...: In [72]: g=gen() In [73]: g.send(10)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-73-98b613a2ec82> in <module>()
----> 1 g.send(10) TypeError: can't send non-None value to a just-started generator In [74]: g.__next__()
enhen
before yield
Out[74]: 'pd the handsome'
# 由上可见,send(xx)并不能用于初始化调用generator, 但是通过 send(None)其实可以,纯粹的相当于74的调用__next__()
# 可见,send方法实际也调用了__next__()从而执行到了下一次的yield
In [75]: g.send(10)
afer yield
before yield
Out[75]: 'pd the handsome' In [76]: g.send(20)
afer yield
before yield
Out[76]: 'pd the handsome'
补充:用send实现协程【来源:寥雪峰】
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK' def produce(c):
c.send(None)
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n) // 执行一次c
print('[PRODUCER] Consumer return: %s' % r)
c.close() c = consumer()
produce(c) 执行结果: [PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK
挺叼,传入个generator做操作!
补充:关于yield from :http://simeonvisser.com/posts/python-3-using-yield-from-in-generators-part-1.html
参考:
http://pymbook.readthedocs.io/en/latest/igd.html
一篇关于yield的好文:
http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do?rq=1
python中的generator, iterator, iterabel的更多相关文章
- python中的generator(coroutine)浅析和应用
背景知识: 在Python中一个function要运行起来,它在python VM中需要三个东西. PyCodeObject,这个保存了函数的代码 PyFunctionObject,这个代表一个虚拟机 ...
- python中生成器generator
通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素 ...
- Python中生成器generator和迭代器Iterator的使用方法
一.生成器 1. 生成器的定义 把所需要值得计算方法储存起来,不会先直接生成数值,而是等到什么时候使用什么时候生成,每次生成一个,减少计算机占用内存空间 2. 生成器的创建方式 第一种只要把一个列表生 ...
- (转)Python中的generator详解
本文转自:http://www.cnblogs.com/xybaby/p/6322376.html 作者:xybaby 注:本文在原文基础上做了一点点修改,仅仅作为个人理解与记忆,建议直接查看原文. ...
- python中的Iterable, Iterator,生成器概念
https://nychent.github.io/articles/2016-05/about-generator.cn 这个深刻 谈起Generator, 与之相关的的概念有 - {list, s ...
- python中的生成器(generator)总结
1.实现generator的两种方式 python中的generator保存的是算法,真正需要计算出值的时候才会去往下计算出值.它是一种惰性计算(lazy evaluation). 要创建一个gene ...
- python中yield用法
在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(constructor). 一.迭代器(iterator) 在Python中,for循环可以用于Python中的任何 ...
- [转]关于Python中的yield
在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(constructor). 一.迭代器(iterator) 在Python中,for循环可以用于Python中的任何 ...
- 【转载】关于Python中的yield
在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(constructor). 一.迭代器(iterator) 在Python中,for循环可以用于Python中的任何 ...
随机推荐
- python中对文件、文件夹的操作需要涉及到os模块和shutil模块。
创建文件:1) os.mknod("test.txt") 创建空文件2) open("test.txt",w) 直接打开一个文件,如果文件不存在则创建文件 创建 ...
- Ruby自学笔记(三)— 方法Method
Ruby做为面向对象语言,肯定要对对象进行相关的操作,这时候就涉及到方法了. 调用方法 - 对象.方法名(实参1,实参2,...,实参n) 方法的分类: 1. 实例方法:顾名思义,就是由实例来调用的方 ...
- while死循环问题-输入字符就会死循环
问题: 是否会遇到这样的问题,在while循环中 sanf("%d",&a);如果输入的不是数字,是字符就会进入死循环. 解决方案:都是缓冲区惹的祸,输入字符后,字符会一直 ...
- PowerShell使用SMTP发送邮件
$smtpServer = "smtp.exmail.qq.com" $smtpUser = "xxxxx@qq.com" $smtpPassword = &q ...
- asp.net web api long running task
http://stackoverflow.com/questions/17577016/long-running-task-in-webapi http://blog.stephencleary.co ...
- JavaScript 项目构建工具 Grunt 实践:安装和创建项目框架
Grunt 是一个基于任务的 JavaScript 项目命令行构建工具,运行于 Node.js 平台.Grunt 能够从模板快速创建项目,合并.压缩和校验 CSS & JS 文件,运行单元测 ...
- angular2 学习笔记 (Typescript - Attribute & reflection)
refer : https://www.npmjs.com/package/reflect-metadata refer : https://www.typescriptlang.org/docs/h ...
- 【转】Javabyte[]数组和十六进制String之间的转换Util------包含案例和代码
原文网址:http://blog.csdn.net/caijunjun1006/article/details/11740223 Java中byte用二进制表示占用8位,而我们知道16进制的每个字符需 ...
- Delphi WEB APP DEBUGGER是如何使用的
WEB APP DEBUGGER是怎么使用的最近在写一个WEBSERVICE的程序,怎么设置使用,WEBAPPDEBUGGER这个工具呢,让别人在调用我的WEBSERVICE的时候我可以调试的?谢 ...
- Java Topology Suite (JTS)与空间数据模型
JTS是Java的处理地理数据的API,它提供以下功能: 实现了OGC关于简单要素SQL查询规范定义的空间数据模型 一个完整的.一致的.基本的二维空间算法的实现,包括二元运算(例如touch和over ...