zoukankan      html  css  js  c++  java
  • Python3 学习第六弹: 迭代器与生成器

    1> 迭代器

    	迭代的意思类似递归一般,不断地对一个对象做重复的操作。来看个例子:
        class Fibs:
            def __init__(self):
                self.last = self.now = 1
            def __iter__(self):  # __iter__定义用来返回一个包含__next_方法的对象。
                return self
            def __next__(self):  # __next__定义返回迭代后的数据,并迭代到下一个
                self.last, self.now = self.now, self.last + self.now
                if self.last>10:
                    raise StopIteration #当没有任何元素时,__next__() 将产生StopIteration异常来告诉 for 语句停止迭代。
                return self.last
        >>> for i in Fibs():
            print(i)
        1
        2
        3
        5
        8
        >>> a = Fibs()
        >>> next(a)
        1
        >>> next(a)
        2
        >>> list(Fibs())
        [1, 2, 3, 5, 8]
    	准确的说,一个实现了__iter__方法的对象是可迭代的,一个实现了__next__方法的对象则是迭代器。
    	定义一个__iter__()方法返回一个具有 __next__() 的对象,如果这个类定义了 __next__() , 那么 __iter__() 仅需要返回 self:
    	通过这样的对__iter__方法和__next__方法的操作,我们完全可以实现个人的Range()的迭代器。
        >>> class Range:
            def __init__(self, times):
                self.count = 0
                self.times = times
            def __iter__(self):
                return self
            def __next__(self):
                if self.count+1 > self.times:
                    raise StopIteration
                self.count += 1
                return self.count-1
        >>> for i in Range(3):
            print(i)
        0
        1
        2

    2> 生成器(generator)——用来创建迭代器的一个方便的工具

    	简单来讲,通过yield能将函数变成生成器函数(generator),python解释器会将其视为generator,在运行的过程中,在每次遇到yield时函数暂停并保存函数所有当前运行信息,返回yield的值。并在下一次__next__方法时从当前位置继续运行。
    
    	一个简单例子:
        >>> def rev():
            yield 1
            yield 2
        >>> a = rev()
        >>> next(a)
        1
        >>> next(a)
        2
        >>> next(a)
        StopIteration # for会将StopIteration作为循环结束标志
    	执行过程:
    	1. 调用生成器函数rev将返回一个生成器
    	2. 第一次调用__next__方法时,函数将在yield 1位置停止,并保存运行的位置及状态,返回1
    	3. 第二次调用__next__方法时,函数从yield 1位置开始运行,再次在yield 2位置停止,并保存运行位置及状态,返回2
    	4. 第三次调用__next__方法时,函数从yield 2位置开始执行,函数结束,不返回值,出现StopIteration错误
    
    	来看一个复杂点的例子:
        >>> def Reverse(data):
                for index in range(len(data)-1, -1, -1):
                    yield data[index]
        >>> for i in Reverse('golf'):
            print(i, end='')
        flog
        >>> Reverse('golf')
        <generator object Reverse at 0x0000000003EC2FC0>
        >>> rev = Reverse('golf')
        >>> next(rev)
        'f'
        >>> next(rev)
        'l'
    	对于上面中用for来遍历这个生成器来说,执行步骤大概是这样的:
    	1. 调用生成器函数将返回一个生成器
    	2. 第一次调用__next__方法时,生成器开始执行,直到遇到yield时暂停,保存生成器函数中的所有执行及状态(对于这个例子来说,生成器函数将会在while循环中暂停,并且保存while执行状态,在下次调用时从当前状态开始执行),并将yield的参数作为返回值。
    	3. 之后再调用__next__方法时,生成器将在上次暂停的地方继续执行。
    	4. 不断循环重复上述两步骤。
    	5. 当调用__next__方法生成器产生StopIteration异常时,for循环结束。
    
    	一个更复杂的例子:(利用递归将多重的列表展开)
        >>> def flat(s):
            try:
                try:
                    s+'' # 判断是否为字符串
                except TypeError:
                    pass
                else:
                    raise TypeError
                for sub in s:
                    for element in flat(sub):
                        yield element
            except TypeError: # 是字符串直接返回
                yield s
        >>> list(flat(['a',[['b'],['c']]]))
        ['a', 'b', 'c']
        >>> list(flat([1,[['2'],3]]))
        [1, '2', 3]
        >>> list(flat([1,[[2],3]]))
        [1, 2, 3]
        >>> list(flat([['Sun', ['Moon']],'god']))
        ['Sun', 'Moon', 'god']

      

  • 相关阅读:
    【2018.05.05 C与C++基础】C++中的自动废料收集:概念与问题引入
    【2018.04.27 C与C++基础】关于switch-case及if-else的效率问题
    【2018.04.19 ROS机器人操作系统】机器人控制:运动规划、路径规划及轨迹规划简介之一
    March 11th, 2018 Week 11th Sunday
    March 10th, 2018 Week 10th Saturday
    March 09th, 2018 Week 10th Friday
    March 08th, 2018 Week 10th Thursday
    March 07th, 2018 Week 10th Wednesday
    ubantu之Git使用
    AMS分析 -- 启动过程
  • 原文地址:https://www.cnblogs.com/Mathics/p/4009823.html
Copyright © 2011-2022 走看看