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中的任何 ...
随机推荐
- Asp.net MVC分页实例
分页是网页基本功能,这里主要讨论在Asp.net MVC环境下分页的前端实现,不涉及后台分页.实现效果如下图显示: Step 1.建立分页信息类 public class PagingInfo { p ...
- JavaScript DES 加密
最近做网页数据加密工作, 使用CryptoJS v3.1.2 这个JavaScript脚本,网上比较有质量的文章实在太少,经验证加密结果与Asp.net DES加密结果一致 参考文章 https:// ...
- VBA读取word中的内容到Excel中
原文:VBA读取word中的内容到Excel中 Public Sub Duqu() Dim myFile As String Dim docApp As Word.Applicati ...
- JavaScript+CSS实现经典的树形导航栏
在一些管理系统里面,一般右侧都会有树形的导航栏,点击一下就会出现下拉菜单,显示出来该父菜单下面的子菜单 项目,然后配以图片,和CSS的效果,可以说是非常常用的功能,现在做一个项目,正好用到这个功能,于 ...
- Solution for "De-serialization exception: Unable to find assembly xxxxx"
public void DeSerialize() { BinaryFormatter formatter = new BinaryFormatter(); AppDomain.CurrentDoma ...
- oracle触发器与:new,:old的使用 --5
:new --为一个引用最新的列值;:old --为一个引用以前的列值; 这两个变量只有在使用了关键字 "FOR EACH ROW"时才存在.且update语句两个都有,而inse ...
- 什么是Socket,为什么要用Socket
应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题.多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据.为了区别不同的应用程序进程和连接 ...
- kvm编译安装及常见问题解决
一.KVM的编译安装 1.安装基本系统和开发工具 1.1 编译内核 mkdir /root/kvm cd /root/kvm wget http://www.kernel.org/pub/linux/ ...
- JSP写入MySQL数据库中出现乱码问题笔记
1.在数据库链接字符串上要形如:jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=UTF-8(注意要加chara ...
- 深入理解java垃圾回收算法
Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...