先来看看如果遇到一个对象,如何判断其是否是这三种类型:
1 from types import GeneratorType 2 from collectiuons import Iterable, Iterator 3 4 isinstance( xx, GeneratorType ) 5 isinstance( xx, Iterable ) 6 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 iobj.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******
参考:
http://pymbook.readthedocs.io/en/latest/igd.html