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']

      

  • 相关阅读:
    GridView动态创建TemplateField的回发问题
    ASP.NET页面生命周期
    php图片叠加
    php文件下载
    mysql 常用操作命令
    转载:图解SQL的Join
    利用iframe来做无刷新上传
    php抽象和接口的区别
    php 循环打开目录读取文件
    mysql存储引擎的对比(一)
  • 原文地址:https://www.cnblogs.com/Mathics/p/4009823.html
Copyright © 2011-2022 走看看