• python中的generator, iterator, iterabel


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

    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 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输送值

     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 <ipython-input-37-98b613a2ec82> in <module>()
    17 ----> 1 g.send(10)
    18 
    19 TypeError: can't send non-None value to a just-started generator
    20 
    21 In [38]: g.__next__(10)
    22 ---------------------------------------------------------------------------
    23 TypeError                                 Traceback (most recent call last)
    24 <ipython-input-38-bc5eb41f1cb6> in <module>()
    25 ----> 1 g.__next__(10)
    26 
    27 TypeError: expected 0 arguments, got 1
    28 
    29 In [39]: g.__next__()            
    30 before x_yield
    31 # 由上可知, “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: 10 35 Out[40]: 20 # 进行到yield x*2 36 37 In [41]: g.__next__() 38 after yield 39 before x_yield 40 41 In [42]: g.send(10) 42 after x_yield: 10 43 Out[42]: 20 44 45 In [43]: g.send(10) # 46 after yield 47 before x_yield 48 49 In [44]: g.send(11) 50 after x_yield: 11 51 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 <ipython-input-73-98b613a2ec82> in <module>()
    15 ----> 1 g.send(10)
    16 
    17 TypeError: can't send non-None value to a just-started generator
    18 
    19 In [74]: g.__next__()
    20 enhen
    21 before yield
    22 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 yield 27 before yield 28 Out[75]: 'pd the handsome' 29 30 In [76]: g.send(20) 31 afer yield 32 before yield 33 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 = 0
    13     while n < 5:
    14         n = n + 1
    15         print('[PRODUCER] Producing %s...' % n)
    16         r = c.send(n)        // 执行一次c
    17         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 OK
    28 [PRODUCER] Producing 2...
    29 [CONSUMER] Consuming 2...
    30 [PRODUCER] Consumer return: 200 OK
    31 [PRODUCER] Producing 3...
    32 [CONSUMER] Consuming 3...
    33 [PRODUCER] Consumer return: 200 OK
    34 [PRODUCER] Producing 4...
    35 [CONSUMER] Consuming 4...
    36 [PRODUCER] Consumer return: 200 OK
    37 [PRODUCER] Producing 5...
    38 [CONSUMER] Consuming 5...
    39 [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

  • 相关阅读:
    bzoj 1004 burnside 引理+DP
    bzoj 3453 数论
    HDU 2899 三分
    HDU 2199 二分
    bzoj 3450 DP
    bzoj 1197 DP
    bzoj 2121 DP
    bzoj 2258 splay
    bzoj 1296 DP
    Memcached的限制和使用建议
  • 原文地址:https://www.cnblogs.com/pengsixiong/p/5841923.html
Copyright © 2020-2023  润新知