zoukankan      html  css  js  c++  java
  • Python基础 迭代器与生成器

    Python基础 迭代器与生成器

    迭代器

    可迭代对象(iterable)

    但凡是可以返回一个迭代器的对象都可称之为可迭代对象,看个例子

    1. >>> x = [1, 2, 3] 
    2. >>> y = iter(x) 
    3. >>> z = iter(x) 
    4. >>> next(y) 

    5. >>> next(y) 

    6. >>> next(z) 

    7. >>> type(x) 
    8. <class 'list'> 
    9. >>> type(y) 
    10. <class 'list_iterator'> 

    这里x是一个可迭代对象,这只是一种通俗的叫法,并不是一种数据类型.
    y和z是两个独立的迭代器,迭代器内部持有一个状态,该状态用于记录当前迭代所在的位置,以方便下次迭代的时候获取正确的元素。

    迭代器(iterator)

    那什么是迭代器呢?它是一个带状态的的对象,他能在你调用next()方法的时候返回容器中的下一个值,任何实现了__iter__() 和 __ next__() 方法的对象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常.

    例子

    1. # 生成无限序列 
    2. >>> from itertools import count 
    3. >>> counter = count(start=13) 
    4. >>> next(counter) 
    5. 13 
    6. >>> next(counter) 
    7. 14 
    1. # 从有限序列中生成无限序列 
    2. >>> from itertools import count 
    3. >>> counter = count(start=13) 
    4. >>> next(counter) 
    5. 13 
    6. >>> next(counter) 
    7. 14 
    1. # 为了更直观地感受迭代器内部的执行过程,我们自定义一个迭代器,以斐波那契数列为例 
    2. class Fib: 
    3. def __init__(self): 
    4. self.prev = 0 
    5. self.curr = 1 
    6.  
    7. def __iter__(self): 
    8. return self 
    9.  
    10. def __next__(self): 
    11. value = self.curr 
    12. self.curr += self.prev 
    13. self.prev = value 
    14. return value 
    15.  
    16. >>> f = Fib() 
    17. >>> list(islice(f, 0, 10)) 
    18. [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] 

    Fib既是一个可迭代对象(因为它实现了__iter__方法),又是一个迭代器(因为实现了__next__方法)。实例变量prev和curr用户维护迭代器内部的状态。每次调用next()方法的时候做两件事:

    1.为下一次调用next()方法修改状态
    2 为当前这次调用生成返回结果

    生成器

    什么是生成器?

      通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

      所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器:generator

      生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。

      生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是,不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器(实际就是迭代器)

    python中的生成器

      要创建一个generator,有很多种方法,第一种方法很简单,只有把一个列表生成式的[]中括号改为()小括号,就创建一个generator

    1. #列表生成式 
    2. lis = [x*x for x in range(10)] 
    3. print(lis) 
    4. #生成器 
    5. generator_ex = (x*x for x in range(10)) 
    6. print(generator_ex) 
    7.  
    8. 结果: 
    9. [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 
    10. <generator object <genexpr> at 0x000002A4CBF9EBA0> 

    那么创建lis和generator_ex,的区别是什么呢?从表面看就是[ ]和(),但是结果却不一样,一个打印出来是列表(因为是列表生成式),而第二个打印出来却是<generator object at 0x000002A4CBF9EBA0>,那么如何打印出来generator_ex的每一个元素呢?

      如果要一个个打印出来,可以通过next()函数获得generator的下一个返回值:

    1.  
    2. #生成器 
    3. generator_ex = (x*x for x in range(10)) 
    4. print(next(generator_ex)) 
    5. print(next(generator_ex)) 
    6. print(next(generator_ex)) 
    7. print(next(generator_ex)) 
    8. print(next(generator_ex)) 
    9. print(next(generator_ex)) 
    10. print(next(generator_ex)) 
    11. print(next(generator_ex)) 
    12. print(next(generator_ex)) 
    13. print(next(generator_ex)) 
    14. print(next(generator_ex)) 
    15. 结果: 




    16. 16 
    17. 25 
    18. 36 
    19. 49 
    20. 64 
    21. 81 
    22. Traceback (most recent call last): 
    23.  
    24. File "列表生成式.py", line 42, in <module> 
    25.  
    26. print(next(generator_ex)) 
    27.  
    28. StopIteration 

      大家可以看到,generator保存的是算法,每次调用next(generaotr_ex)就计算出他的下一个元素的值,直到计算出最后一个元素,没有更多的元素时,抛出StopIteration的错误,而且上面这样不断调用是一个不好的习惯,正确的方法是使用for循环,因为generator也是可迭代对象:

    1. #生成器 
    2. generator_ex = (x*x for x in range(10)) 
    3. for i in generator_ex: 
    4. print(i) 
    5.  
    6. 结果: 




    7. 16 
    8. 25 
    9. 36 
    10. 49 
    11. 64 
    12. 81 

      所以我们创建一个generator后,基本上永远不会调用next(),而是通过for循环来迭代,并且不需要关心StopIteration的错误,generator非常强大,如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

      这里说一下generator和函数的执行流程,函数是顺序执行的,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次被next()调用时候从上次的返回yield语句处急需执行,也就是用多少,取多少,不占内存。

  • 相关阅读:
    不用写代码的框架
    bat执行python脚本,执行多条命令
    VMware-workstation-full-15.1.0-13591040安装破解-附件密钥
    w10谷歌chrome关闭自动更新
    谷歌安装提示已经安装高版本解决
    python项目三方库导出导入 requirements.txt文件
    点阴影
    goto gamedev blog
    20135315-信息安全系统设计基础第五周学习总结
    win10 +python3.6环境下安装opencv以及pycharm导入cv2有问题的解决办法
  • 原文地址:https://www.cnblogs.com/FelixTeng/p/9898039.html
Copyright © 2011-2022 走看看