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

    1.1.概念

     迭代器协议

    • 迭代器协议:对象需要提供next方法,它要么返回迭代中的下一项,要么引起一个StopIteration异常,以终止迭代
    • 可迭代对象:实现了迭代器协议的对象

     迭代器

    • 迭代器是访问集合内元素的一种方式,一般用来遍历数据
    • 迭代器和以下标的访问方式不一样,迭代器是不能返回的(比如下标方式 list[2],之后可以访问list[0],list[1],只能__next__),迭代器提供了一种惰性方式获取数据(就是只有在访问数据的时候才去计算或者说才去获取数据)

    生成器

    • python使用生成器对延迟操作提供了支持,所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果。这也是生成器的主要好处

    生成器函数

    • 与常规函数不同的是:使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数,下次执行的时候,从上一次挂起地方开始。

    生成器表达式

    • 返回的是一个生成器对象,这个对象只有在需要的时候才产生结果

    1.2. 迭代器必须实现iter()方法

    Python中 list,truple,str,dict这些都可以被迭代,但他们并不是迭代器。为什么?

    因为和迭代器相比有一个很大的不同,list/truple/map/dict这些数据的大小是确定的,也就是说有多少事可知的。但迭代器不是,迭代器不知道要执行多少次,所以可以理解为不知道有多少个元素,每调用一次next(),就会往下走一步,是惰性的。

    • Iterable:判断是不是可以迭代
    • Iterator:判断是不是迭代器
    from collections.abc import Iterable,Iterator
    
    a = [1,2,]
    
    print(isinstance(a,Iterable))    #True    list是可迭代的
    print(isinstance(a,Iterator))    #False   list不是迭代器 

     通过iter()方法,获取iterator对象

    from collections.abc import Iterable,Iterator
    
    a = [1,2,]
    
    iter_rator = iter(a)
    print(isinstance(a,Iterable))             #True         可迭代的
    print(isinstance(iter_rator,Iterator))    # True        迭代器
    
    
    print(isinstance((x for x in range(10)),Iterator))     #True
    
    # 总结 # 凡是可以for循环的,都是Iterable # 凡是可以next()的,都是Iterator # list,truple,dict,str,都是Itrable不是Iterator,但可以通过iter()函数获得一个Iterator对象
    class Iterable(metaclass=ABCMeta):
    
        __slots__ = ()
    
        @abstractmethod
        def __iter__(self):
            while False:
                yield None
    
        @classmethod
        def __subclasshook__(cls, C):
            if cls is Iterable:
                return _check_methods(C, "__iter__")
            return NotImplemented
    Iterable源码

    1.3.自定义迭代器

    通过自定义一个迭代器,进一步说明什么是迭代器,什么是可迭代对象

    from collections.abc import Iterator
    
    class Company(object):
        def __init__(self, employee_list):
            self.employee = employee_list
    
        def __iter__(self):
            return MyIterator(self.employee)
    
    #自定义迭代器
    class MyIterator(Iterator):         #如果不继承Iterator,则必须实现__iter__方法
        def __init__(self, employee_list):
            self.iter_list = employee_list
            self.index = 0   #初始化索引位置
    
        def __next__(self):
            #真正返回迭代值的逻辑
            try:
                word = self.iter_list[self.index]
            except IndexError:
                raise StopIteration
            self.index += 1
            return word
    
    if __name__ == "__main__":
        company = Company(["derek1", "derek2", "derek3"])
        my_itor = iter(company)
        
        print(next(my_itor))     #derek1
        print(next(my_itor))     #derek2
        print(next(my_itor))     #derek3
        
        for item in company:
            print (item)         #derek1  derek2  derek3

     1.4.生成器函数的使用

     (1)生成器函数和普通函数的区别

    #函数里只要有yield关键字,就是生成器函数
    def gen_func():
        yield 1
    
    def func():
        return 1
    
    
    if __name__ == '__main__':
        
        gen = gen_func()   
        print(type(gen))     #<class 'generator'>   返回的是一个生成器对象
        
        res = func()
        print(type(res))     #<class 'int'>    返回1
        pass

     (2)取出生成器里面的值

    #函数里只要有yield关键字,就是生成器函数
    def gen_func():
        yield 1
        yield 2
        yield 3
    
    
    if __name__ == '__main__':
    
        gen = gen_func()
        print(type(gen))     #<class 'generator'>   返回的是一个生成器对象
    
        for value in gen:
            print(value)     # 1,2,3

     (3)斐波那契的例子

    def fib(index):
        re_list = []
        n,a,b = 0,0,1
        while n < index:
            re_list.append(b)
            a,b = b, a+b
            n += 1
        return re_list
    
    print(fib(10))    #[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

     假如当数据量非常大的时候,这样全部打印会消耗非常大的内存,下面使用yield,虽然同样是获取数据,但是它实际上是不消耗内存的

    def gen_fib(index):
        n,a,b = 0,0,1
        while n < index:
            yield b       
            a,b = b, a+b
            n += 1
    
    for data in gen_fib(10):
        print(data)   # 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
  • 相关阅读:
    React在componentDidMount里面发送请求
    React 术语词汇表
    React里受控与非受控组件
    React和Vue等框架什么时候操作DOM
    【LeetCode】79. Word Search
    【LeetCode】91. Decode Ways
    【LeetCode】80. Remove Duplicates from Sorted Array II (2 solutions)
    【LeetCode】1. Two Sum
    【LeetCode】141. Linked List Cycle (2 solutions)
    【LeetCode】120. Triangle (3 solutions)
  • 原文地址:https://www.cnblogs.com/liqianglog/p/11097545.html
Copyright © 2011-2022 走看看