zoukankan      html  css  js  c++  java
  • 迭代器和生成器

    迭代器实现

    # for 循环遍历列表、元组和字典等,这些对象都是可迭代的,因此它们都属于迭代器
    '''__iter__(self):该方法返回一个迭代器(iterator),迭代器必须包含一个__next__()方法,
    该方法返回迭代器的下一个元素。''' 
    
    """__reversed__(self):该方法主要为内建的 reversed() 反转函数提供支持,
    当程序调用 reversed() 函数对指定迭代器执行反转时,实际上是由该方法实现的。"""
    
    # 定义一个代表斐波那契数列的迭代器
    class Fibs:
        def __init__(self, len):
            self.first = 0
            self.sec = 1
            self.__len = len
        # 定义迭代器所需的__next__方法
        def __next__(self):
            # 如果__len__属性为0,结束迭代
            if self.__len == 0:
                raise StopIteration
            # 完成数列计算:
            self.first, self.sec = self.sec, self.first + self.sec
            # 数列长度减1
            self.__len -= 1
            return self.first
        # 定义__iter__方法,该方法返回迭代器
        def __iter__(self):
            return self
    # 创建Fibs对象
    fibs = Fibs(10)
    # 获取迭代器的下一个元素
    print(next(fibs))
    # 使用for循环遍历迭代器
    for el in fibs:
        print(el, end=' ')
    
    
    # 将列表转换为迭代器
    my_iter = iter([3,4,5,'java'])
    
    # 依次获取迭代器的下一个元素
    print(my_iter.__next__()) # 3
    print(my_iter.__next__()) # 4

    生成器

    # 创建生成器需要两步操作:
    # 1.定义一个包含 yield 语句的函数。
    # 2.调用第 1 步创建的函数得到生成器
    def test(val, step):
        print("--------函数开始执行------")
        cur = 0
        # 遍历0~val
        for i in range(val):
            # cur添加i*step
            cur += i * step
            # print(cur,end=' ')
            yield cur
    
    # yield cur 语句的作用有两点:
    #    每次返回一个值,有点类似于 return 语句。
    #    冻结执行,程序每次执行到 yield 语句时就会被暂停。
    
    """在程序被 yield 语句冻结之后,当程序再次调用 next() 函数获取生成器的下一个值时,
    程序才会继续向下执行。"""
    """需要指出的是,调用包含 yield 语句的函数并不会立即执行,它只是返回一个生成器。
    只有当程序通过 next() 函数调用生成器或遍历生成器时,函数才会真正执行。"""
    
    # 执行函数,返回生成器
    t = test(10, 2)
    print('=================')
    # 获取生成器的第一个值
    print(next(t)) # 0,生成器“冻结”在yield处
    print(next(t)) # 2,生成器再次“冻结”在yield处
    
    """从上面的输出结果不难看出,当程序执行 t = test(10, 2) 调用函数时,
    程序并未开始执行 test() 函数;当程序第一次调用 next(t) 时,test() 函数才开始执行。
    Python 2.x 不使用 next() 函数来获取生成器的下一个值,而是直接调用生成器的 next() 方法。
    也就是说,在 Python 2.x 中应该写成 t.next()。
    
    当程序调用 next(t) 时,生成器会返回 yield cur 语句返回的值(第一次返回 0),
    程序被“冻结”在 yield 语句处,因此可以看到上面生成器第一次输出的值为 0。
    
    当程序第二次调用 next(t) 时,程序的“冻结”被解除,继续向下执行,这一次循环计数器 i 变成 1,
    在执行 cur += i * step 之后,cur 变成 2 ,
    生成器再次返回 yield cur 语句返回的值(这一次返回 2),
    程序再次被“冻结”在该 yield 语句处,因此可以看到上面生成器第二次输出的值为 2。
    """
    
    # 由于前面两次调用 next() 函数已经获取了生成器的前两个值,因此此处循环时第一次输出的值就是 6
    for x in t:
        print(x,end=' ')#6 12 20 30 42 56 72 90
    
    print("***************************")
    #再次创建生成器
    t = test(10, 1)
    #将生成器转换成列表
    print (list (t))
    #再次创建生成器
    t = test(10, 3)
    #将生成器转换成元组
    print(tuple(t))
    
    
    """
    使用生成器的优势:
    1.当使用生成器来生成多个数据时,程序是按需获取数据的,它不会一开始就把所有数据都生成出来,
    而是每次调用 next() 获取下一个数据时,生成器才会执行一次,因此可以减少代码的执行次数。
    比如前面介绍的示例,程序不会一开始就把生成器函数中的循环都执行完成,
    而是每次调用 next() 时才执行一次循环体。
    2.当函数需要返回多个数据时,如果不使用生成器,程序就需要使用列表或元组来收集函数返回的多个值,
    当函数要返回的数据量较大时,这些列表、元组会带来一定的内存开销。
    如果使用生成器就不存在这个问题,生成器可以按需、逐个返回数据。
    3.使用生成器的代码更加简洁。
    """
  • 相关阅读:
    Python3-笔记-E-005-库-系统os
    Python3-笔记-E-004-库-日历calendar
    Python3-笔记-E-003-库-日期时间datatime
    Python3-笔记-E-002-库-Unix纪元时间戳time
    Python3-笔记-E-001-库-随机数random
    Python3-笔记-D-001-异常与断言
    Python3-笔记-C-007-函数-导入模块并调用
    【bzoj2199/Usaco2011 Jan】奶牛议会——2-sat
    【bzoj1578/Usaco2009 Feb】Stock Market 股票市场——完全背包
    【bzoj1741/Usaco2005 nov】Asteroids 穿越小行星群——最小割
  • 原文地址:https://www.cnblogs.com/jzxs/p/11414342.html
Copyright © 2011-2022 走看看