zoukankan      html  css  js  c++  java
  • 【Python之路】特别篇--生成器(constructor)、迭代器(iterator)、可迭代对象(iterable)

    生成器(constructor)

      生成器函数在Python中与迭代器协议的概念联系在一起。包含yield语句的函数会被特地编译成生成器 !!!

      当函数被调用时,他们返回一个生成器对象,这个对象支持迭代器接口。

      不像一般的函数会生成值后退出,生成器函数在生成值后会自动挂起并暂停他们的执行和状态,他的本地变量将保存状态信息,这些信息在函数恢复时将再度有效

    创建生成器方式有两种:

    方法一:

    s = ( x for x in range(5) )

    方法二:

    def foo():
        print('OK')
        yield 1
    

    例子:

    def g(n):
        for i in range(n):
            yield i **2
    
    for i in g(5):
        print(i)
    

    要了解他的运行原理,我们来用next方法看看:

    t = g(5)
    print(t.__next__())      # 0 
    print(t.__next__())      # 1 
    print(t.__next__())      # 4 
    print(t.__next__())      # 9 
    print(t.__next__())      # 16 
    print(t.__next__())
    
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration

    在运行完5次next之后,生成器抛出了一个StopIteration异常,迭代终止。

    send(msg) 与 next()

    了解了next()如何让包含yield的函数执行后,我们再来看另外一个非常重要的函数send(msg)。

    其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做

    c.next() 和 c.send(None) 作用是一样的。

    def g(n):
        for i in range(n):
            ret = yield i **2
            print(ret)
    
    
    t = g(5)
    print(t.__next__())
    print(t.send('Hello'))
    
    # 0 Hello 1
    

    需要注意的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有yield语句来接收这个值。

    send(msg) 和 next()是有返回值的,它们的返回值很特殊,返回的是yield表达式的参数 !

    执行顺序是:遇到yield 先返回值,等下次再进入时再用 msg 进行赋值!!!

    再来看一个yield的例子,用生成器生成一个Fibonacci数列:

    def fab(max):
        a, b = 0, 1
        while a < max:
            yield a
            a, b = b, a + b
    
    for i in fab(20):
        print(i)
    
    # 0 1 1 2 3 5 8 13
    

    另一个 yield 的例子来源于文件读取。

     def read_file(fpath): 
        BLOCK_SIZE = 1024 
        with open(fpath, 'rb') as f: 
            while True: 
                block = f.read(BLOCK_SIZE) 
                if block: 
                    yield block 
                else: 
                    return
    

      

    迭代器(iterator)

      for循环可以用于Python中的任何类型,包括列表、元组等等,实际上,for循环可用于任何“可迭代对象”!

      迭代器是一个实现了迭代器协议的对象,Python中的迭代器协议就是有next方法的对象会前进到下一结果,而在一系列结果的末尾是,则会引发StopIteration。

      任何这类的对象在Python中都可以用for循环或其他遍历工具迭代,迭代工具内部会在每次迭代时调用next方法,并且捕捉StopIteration异常来确定何时离开。

      使用迭代器一个显而易见的好处就是:每次只从对象中读取一条数据,不会造成内存的过大开销。

    注意

      判断迭代器的条件是:

    1. 有__iter__ 方法

    2. 有__next__ 方法

      所有的生成器都是迭代器!

    迭代器例子:

    比如要逐行读取一个文件的内容,利用readlines()方法,我们可以这么写:

    for line in open("test.txt").readlines():
        print (line)
    

    这样虽然可以工作,但不是最好的方法。因为他实际上是把文件一次加载到内存中,然后逐行打印。当文件很大时,这个方法的内存开销就很大了。

    利用file的迭代器,我们可以这样写:

    for line in open("test.txt"): 
        print (line)
    

    这是最简单也是运行速度最快的写法,他并没显式的读取文件,而是利用迭代器每次读取下一行。

    for 循环实质

    1. 调用 __iter__ 方法将可迭代对象转换成迭代器

    2. 对迭代器对象不断调用 __next__ 方法

    3. 处理StopIteration 异常

    class Fab(object): 
        def __init__(self, max): 
            self.max = max 
            self.n, self.a, self.b = 0, 0, 1 
    
        def __iter__(self): 
            return self 
    
        def __next__(self): 
            if self.n < self.max: 
                r = self.b 
                self.a, self.b = self.b, self.a + self.b 
                self.n = self.n + 1 
                return r 
            raise StopIteration()
    
    
    '''
    >>> for key in Fabs(5):
        print key
     
         
    1
    1
    2
    3
    5
    '''
    View Code

    可迭代对象(iterable)

      判断条件:内部具有 __iter__ 方法

    from collections import Iterable,Iterator
    print(isinstance(range(1),Iterable))
    print(isinstance(range(1),Iterator))
    
    print(isinstance(list(),Iterable))
    print(isinstance(list(),Iterator))
    

      

  • 相关阅读:
    DGA域名可以是色情网站域名
    使用cloudflare加速你的网站隐藏你的网站IP
    167. Two Sum II
    leetcode 563. Binary Tree Tilt
    python 多线程
    leetcode 404. Sum of Left Leaves
    leetcode 100. Same Tree
    leetcode 383. Ransom Note
    leetcode 122. Best Time to Buy and Sell Stock II
    天津Uber优步司机奖励政策(12月28日到12月29日)
  • 原文地址:https://www.cnblogs.com/5poi/p/6785785.html
Copyright © 2011-2022 走看看