zoukankan      html  css  js  c++  java
  • [python]--迭代器,生成器补充

      在python中,list,string,dict都是可迭代对象,可以通过for语句遍历.

    迭代器

      迭代器对象要求支持迭代器协议的对象,在python中,支持迭代器协议就算实现对象的__iter__()和next()方法.其中__iter__()方法返回迭代器对象本身;

      next()方法返回容器的下一个元素,在结尾时引发StopIteration异常

      __iter__()和next()方法

      这两个方法是迭代器最基本的方法,一个用来获得迭代器对象,一个用来获取容器中的下一个元素.

      对于可迭代对象,可以使用内建函数iter()来获取它的迭代器对象:

      

      iter()方法可以获得list的迭代器对象,然后就可以使用__next__()方法来访问list中的元素了.当容器中没有可访问的元素后,__next__()方法就会抛出一个

      StopIteration异常终止迭代器.

      不使用iter()方法的话,可以使用next()方法对可迭代对象,来获取下一个元素

      自定义迭代器

        了解了迭代器协议之后,就可以自定义迭代器了.

        下面例子中实现了一个MyRange的类型,这个类型中实现了__iter__()方法,通过这个方法返回对象本身作为迭代器对象;同时,实现了next()方法用来获取容器中的下一个元素,当没有可访问元素后,就抛出StopIteration异常.

        

    class MyRange(object):
        def __init__(self, n):
            self.idx = 0
            self.n = n
            
        def __iter__(self):
            return self
            
        def next(self):
            if self.idx < self.n:
                val = self.idx
                self.idx += 1
                return val
            else:
                raise StopIteration()

      这个自定义类型跟内建函数xrange很类似,看一下运行结果:

        

      生成器

      在python中,使用生成器可以很方便的支持迭代器协议.生成器通过生成器函数产生,生成器函数可以通过常规的def语句来定义,但是不用return返回,而是用yield一次返回一个结果,在每个结果之间挂起和继续它们的状态,来自动实现迭代协议.

      也就是说,yield是一个语法糖.内部实现支持了迭代器协议,同时yield内部是一个状态机,维护着挂起和继续的状态.

      下面看看生成器的使用:

      

      在这个例子中,定义了一个生成器函数,函数返回一个生成器对象,然后就可以通过for语句进行迭代访问.

      其实,生成器函数返回生成器的迭代器,"生成器的迭代器"这个术语通常被称作"生成器".要注意的是生成器就算一类特殊的迭代器.作为一个迭代器,生成器必须要定义一些方法,其中一个就是next().如同迭代器一样,我们可以使用next()函数获取下一个值.

      生成器执行流程

    • 当调用生成器函数的时候,函数只是返回了一个生成器对象,并没有执行.
    • 当next()方法第一次被调用的时候,生成器函数才开始执行,执行到yield语句处停止
      •   next()方法的返回值就是yield语句处的参数(yielded value)    
    • 当继续调用next()方法的时候,函数将接着上一次停止的yield语句处继续执行,并到下一个yield处停止;如果后面没有yield就抛出StopIteration异常

    生成器表达式

      在开始介绍生成器表达式之前,先看看我们比较熟悉的列表解析(List comprehensions),列表解析一般都是下面的形式.

      [expr for iter_var in iterable if cond_expr]

      迭代iterable里所有内容,每一次迭代后,把iterable里满足cond_expr条件的内容放到iter_var中,再在表达式expr中应该iter_var的内容,最后用表达式的计算值生存一个列表.

      例如,生成一个list来保存50以内的所有奇数:

      [i for i in range(50) if i%2]

      生成器表达式是在python2.4中引入的,当序列过长,而每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析.生成器表达式的语法和列表解析一样,只不过生成器表达式是被()括起来的,而不是[],如下:

      (expr for iter_var in iterable if cond_expr)

      生成器表达式并不是创建一个列表,而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目"产生"(yield)出来,生成器表达式使用惰性计算,只有在检索时才被赋值,所以在列表比较长的情况下使用内存上更有效

      生成器表达式产生的生成器,自身是一个可迭代对象,同时也是迭代器本身

      递归生成器

        生成器可以向函数一样进行递归使用,下面看一个简单的例子,对一个序列进行全排列:

      

    def permutations(li):
        if len(li) == 0:
            yield li
        else:
            for i in range(len(li)):
                li[0], li[i] = li[i], li[0]
                for item in permutations(li[1:]):
                    yield [li[0]] + item
        
    for item in permutations(range(3)):
        print item

      生成器的send()和close()方法

        生成器中还有两个很重要的方法:send()和close()

        send(value):

          从前面了解到,next()方法可以恢复生成器状态并继续执行,其实send()是除next()外另一个恢复生成器的方法.

          python2.5中,yield语句变成了yield表达式,也就是说yield可以有一个值,而这个值就是send()方法的参数,所以send(None)和next()是等效的.同样,next()和send()的返回值都是yield语句处的参数

          关于send():调用send传入非None值前,生成器必须处于挂起状态,否则将抛出异常

        close():

          这个方法用来关闭生成器,对关闭的生成器后再调用next或send将抛出异常

      

    人生短短数十载,经不起几次重头再来
  • 相关阅读:
    控件(View)之TextView, Button, ImageButton, ImageView, CheckBox, RadioButton, AnalogClock, DigitalClock【转】
    Android 基础知识
    Intent 的用法
    Layout 和 Menu【转】
    第一讲 深入struts的配置
    第二讲 struts的拦截器
    第三讲 struts验证框架
    vscode Python 无法导入beautifulsoup4解决方案 (bs4报错:vscode unresolved import 'beautifulsoup4')
    BUUCTF RE [GUETCTF2019]re
    Typora破解复现
  • 原文地址:https://www.cnblogs.com/bk770466199/p/6642273.html
Copyright © 2011-2022 走看看