博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python中的generator, iterator, iterabel
阅读量:5276 次
发布时间:2019-06-14

本文共 7883 字,大约阅读时间需要 26 分钟。

先来看看如果遇到一个对象,如何判断其是否是这三种类型:

1 from types import GeneratorType2 from collectiuons import Iterable, Iterator3 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]: generatorIn[8]: dir(ge)Out[8]: [ ...,'__iter__', 'next', ... ]     In[9]: isinstance(ge, collections.Iterator)Out[9]: True

  生成器的一个特点是只能用一次

In[11]: for i in ge: ...     print i...     012345In[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 "
", line 1, in
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 "
" 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 += 1obj = 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                                                                     
after yield before yield
after yield before yield
after yield *****end******

 

补充:

  关于generator的yield与send:

  总的来说:yield返回的是个generator对象,send是向generator输送值

1 In [35]: def gen(): 2     ...:     while True: 3     ...:         print("before x_yield") 4     ...:         x=yield 5     ...:         print("after x_yield:", x) 6     ...:         yield x*2 7     ...:         print("after yield") 8     ...:          9     ...:       10 11 In [36]: g = gen()12 13 In [37]: g.send(10)14 ---------------------------------------------------------------------------15 TypeError                                 Traceback (most recent call last)16 
in
()17 ----> 1 g.send(10)18 19 TypeError: can't send non-None value to a just-started generator20 21 In [38]: g.__next__(10)22 ---------------------------------------------------------------------------23 TypeError Traceback (most recent call last)24
in
()25 ----> 1 g.__next__(10)26 27 TypeError: expected 0 arguments, got 128 29 In [39]: g.__next__() 30 before x_yield31 # 由上可知, “x=yield”中的yield也会成为__next__()调用的终点,也就是说如果上面要两个__next__()才能走完。 31 # 通过实验发现,其实x=yield的执行并不是同时的,比如send(10),此时相当于到达了x=yield中的yield,而此时再执行send(11)才会执行x=yield这个赋值操作 31 # 所以输出是22而不是第一次就能传入的20【见43,44的输出】32 33 In [40]: g.send(10) 34 after x_yield: 1035 Out[40]: 20 # 进行到yield x*236 37 In [41]: g.__next__()38 after yield39 before x_yield40 41 In [42]: g.send(10)42 after x_yield: 1043 Out[42]: 2044 45 In [43]: g.send(10) #46 after yield47 before x_yield48 49 In [44]: g.send(11)50 after x_yield: 1151 Out[44]: 22

 

补充:关于send与__next__()

1 In [71]: def gen(): 2     ...:     print("enhen") 3     ...:     while True: 4     ...:         print("before yield") 5     ...:         yield "pd the handsome" 6     ...:         print("afer yield") 7     ...:          8  9 In [72]: g=gen()10 11 In [73]: g.send(10)12 ---------------------------------------------------------------------------13 TypeError                                 Traceback (most recent call last)14 
in
()15 ----> 1 g.send(10)16 17 TypeError: can't send non-None value to a just-started generator18 19 In [74]: g.__next__()20 enhen21 before yield22 Out[74]: 'pd the handsome' 23 # 由上可见,send(xx)并不能用于初始化调用generator, 但是通过 send(None)其实可以,纯粹的相当于74的调用__next__()24 # 可见,send方法实际也调用了__next__()从而执行到了下一次的yield 25 In [75]: g.send(10)26 afer yield27 before yield28 Out[75]: 'pd the handsome'29 30 In [76]: g.send(20)31 afer yield32 before yield33 Out[76]: 'pd the handsome'

 

补充:用send实现协程【】

1 def consumer(): 2     r = '' 3     while True: 4         n = yield r 5         if not n: 6             return 7         print('[CONSUMER] Consuming %s...' % n) 8         r = '200 OK' 9 10 def produce(c):11     c.send(None)12     n = 013     while n < 5:14         n = n + 115         print('[PRODUCER] Producing %s...' % n)16         r = c.send(n)        // 执行一次c17         print('[PRODUCER] Consumer return: %s' % r)18     c.close()19 20 c = consumer()21 produce(c)22 23 执行结果:24 25 [PRODUCER] Producing 1...26 [CONSUMER] Consuming 1...27 [PRODUCER] Consumer return: 200 OK28 [PRODUCER] Producing 2...29 [CONSUMER] Consuming 2...30 [PRODUCER] Consumer return: 200 OK31 [PRODUCER] Producing 3...32 [CONSUMER] Consuming 3...33 [PRODUCER] Consumer return: 200 OK34 [PRODUCER] Producing 4...35 [CONSUMER] Consuming 4...36 [PRODUCER] Consumer return: 200 OK37 [PRODUCER] Producing 5...38 [CONSUMER] Consuming 5...39 [PRODUCER] Consumer return: 200 OK

挺叼,传入个generator做操作!

 

补充:关于yield from :

 

 

参考:

  

一篇关于yield的好文:

  

转载于:https://www.cnblogs.com/pengsixiong/p/5841923.html

你可能感兴趣的文章