• Python:迭代器


    迭代器

     

    本节进行迭代器的讨论。只讨论一个特殊方法---- __iter__  ,这个方法是迭代器规则的基础。

     

    迭代器规则

    迭代的意思是重复做一些事很多次---就像在循环中做的那样。__iter__ 方法返回一个迭代器,所谓迭代器就是具有next方法的对象,在调用next方法时,迭代器会返回它的下一个值。如果next方法被调用,但迭代器没有值可以返回,就会引发一个StopIteration异常。

     

    这里是一个婓波那契数例,使用迭代器如下:

    复制代码
    class Fibs:
        def __init__(self):
            self.a = 0
            self.b = 1
        def next(self):
            self.a , self.b = self.b , self.a + self.b
            return self.a
        def __iter__(self):
            return self
    
    >>> fibs = Fibs() 
    >>> for f in fibs:
          if  f  > 1000:
              print f
              break    #因为设置了break ,所以循环在这里停止。
    
    1597
    复制代码

    内建函数iter可以从可迭代的对象中获得迭代器。

    >>> it = iter([1,2,3])
    >>> it.next()
    1
    >>> it.next()
    2

     

    从迭代器得到序列

    除了在迭代器和可迭代对象上进行迭代外,还能把它们转换为序列。在大部分能使用序列的情况下,能使用迭代器替换。

    复制代码
    class TestIterator:
        value = 0
        def next(self):
            self.value += 1
            if self.value > 10: raise StopIteration
            return self.value
        def __iter__(self):
            return self
    
    >>> ti = TestIterator()
    >>> list(ti)
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    复制代码

     

     

     

    生成器

     

    生成器也叫 简单生成器,生成器可以帮助读者写出非常优雅的代码,当然,编写任何程序时不使用生成器也是可以的。

     

    创建生成器

    创建一个生成器就像创建函数一样简单。

    复制代码
    >>> def flatten(nested):
        for sublist in nested:
            for element in sublist:
                yield element
    
                
    >>> nested = [[1,2],[3,4],[5]]
    #使用for循环
    >>> for num in flatten(nested):
        print num
    
        
    1
    2
    3
    4
    5
    #或使用list函数
    >>> list(flatten(nested))
    [1, 2, 3, 4, 5]
    复制代码

     

    递归生成器

    上面创建的生成器只能处理两层嵌套,为了处理嵌套使用了两个for循环,如果要处理任意层的嵌套呢?例如,可以每层嵌套需要增加一个for循环,但不知道有几层嵌套,所以必须把解决方案变得更灵活,现在可以用递归来解决。

    复制代码
    >>> def fla(aa):
        try:
            for bb in aa:
                for cc in fla(bb):
                    yield cc
        except TypeError:
            yield aa
    
    >>> list(fla([[[1],2],3,4,[5,[6,7]],8]))  #注意括号层次比较多
    [1, 2, 3, 4, 5, 6, 7, 8]
    复制代码

      

    fla被调用时有两种情况:基本情况和需要递归的情况

      在基本的情况中,函数被告知展开一个元素,这种情部下,for循环会引发一个TypeError 异常,生成会产生一个元素。

      如果展开的是一个列表,那么就需要特殊情况处理。程序必须遍历所有的子列表,并对它们调用fla

    -------------------

    上面的做法有一个问题:如果aa 是一个类似于字符串的对象(字符串、UnicodeUserString等),那么它就是一个序列,不会引发TypeError,但是你不想对这样的对象进行迭代。

    为了处理这种情况,则必须在生成器的开始处添加一个检查语句。试着将传入的对象和一个字符串拼接,看看会不会出现TypeError,这是检查一个对象是不是类似于字符串最简单快速的方法。

    复制代码
    >>> def flatten(nested):
        try:
           #不要迭代类似字符串的对象
            try:nested + ''
            except TypeError: pass
            else: raise TypeError
            for sublist in nested:
                for element in flatten(sublist):
                    yield element
        except TypeError:
            yield nested
    
            
    >>> list(flatten(['foo',['bar',['baz']]]))
    ['foo', 'bar', 'baz']
    复制代码

    如果nested+’’ 引发了一个TypError ,它就会被忽略。如果没有引发TypeError,那么内层try语句就会引发一个它自己的TypeError异常。

     

     

    生成器方法

    生成器新属性是在开始运行后为生成器提供值的能力。表现为生成器和“外部世界”进行交流的渠道:

      * 外部作用域访问生成器的send方法,就像访问next 方法一样,只不过前者使用一个参数(发送的“消息”---任意对象)

      * 在内部则挂起生成器,yield现在作为表达式而不是语句使用,换句话说,当生成器重新运行的时候,yield方法返回一个值,也就是外部通过send方法发送的值。如果next 方法被使用,那么yield方法返回None. 

    下面简单的方例子来说明这种机制:

    复制代码
    >>> def repeater(value):
        while True:
            new =(yield value)
            if new is not None:value = new
    
            
    >>> r = repeater(42)
    >>> r.next()
    42
    >>> r.send("hello, world!")
    'hello, world!'
    复制代码

    生成器的另两个方法:

      * throw方法(使用异常类型调用,还有可选的值以及回溯对象)用于在生成器内引发一个异常(在yield表达式中)

      * close 方法(调用时不用参数)用于停止生成器。

     

  • 相关阅读:
    Mac查看某个文件的中某关键字信息
    Mac查看所有的文件
    Mac查看当前用户的环境变量
    Mac安装maven
    Lombok使用坑之属性不区分大小写
    Mac常用软件列表
    Mac系统升级
    Mac安装Git
    Mac查看git的安装路径
    Mac安装JDK8
  • 原文地址:https://www.cnblogs.com/baoendemao/p/3804662.html
Copyright © 2020-2023  润新知