生成器generator和迭代器Iterator

一、列表生成式
       在学习生成器迭代器之前先了解一下什么是列表生成式,列表生成式是Python内置的非常简单却强大的可以用来创建list的生成式。什么意思?举个例子,如果想生成列表[0,1,2,3,4,5]可以使用list(range(6)),但是如果想要生成[,,,,,]即[0,1,4,9,16,25]怎么做?

#方法一:循环
>>> L = []
>>> for x in range(6):
... L.append(x**2)
...
>>> L
[0, 1, 4, 9, 16, 25]
#方法二:列表生成式
>>> [x**2 for x in range(6)]
[0, 1, 4, 9, 16, 25]
        观察方法一、方法二可以发现,使用方法二列表生成式更为简洁、明了,方法二就是列表生成式。再来几个例子加深理解:

#计算正整数0-5之间偶数平方
>>> [x**2 for x in range(6) if x%2==0]
[0, 4, 16]

#列表生成式使用两个变量
>>> d = {‘a‘:‘1‘,‘b‘:‘2‘,‘c‘:‘3‘}
>>> [k+‘=‘+v for k,v in d.items()]
[‘a=1‘, ‘b=2‘, ‘c=3‘]
二、生成器
       通过列表生成式,可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

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

1.如何创建生成器

  方法一:创建生成器最简单的方法就是把一个列表生成式的 [] 改为 () ,就创建了一个生成器: 

#列表生成式
>>> L = [x**2 for x in range(6)]
>>> L
[0, 1, 4, 9, 16, 25]

#生成器
>>> g = (x**2 for x in range(6))
>>> g
<generator object <genexpr> at 0x00000173FFBFA1A8>

注:L与g的区别仅在于最外层的[]和(),L是一个列表,而g是一个生成器。

     方法二:要把普通函数变为生成器(generator),只需把 print(b) 改为 yield b 就可以了。 如果一个函数中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个生成器(generator)。

2.如何获得生成器的每一个元素?

方法一:如果要一个一个打印出来,可以通过 next() 函数获得生成器的下一个返回值。生成器保存的是算法,每次调用next(),就计算g的下一个元素的值,直到计算到最后一个元素,没有更多元素时,抛出StopIteration错误。

#通过next()获得生成器的每一个元素
>>> g = (x**2 for x in range(6))
>>> g
<generator object <genexpr> at 0x00000173FFBFA1A8>
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

  方法二:使用for循环

#通过for循环获得生成器的每一个值
>>> g = (x**2 for x in range(6))
>>> for i in g:
...     print(i)
...
0
1
4
9
16
25

3.生成器实例

练习一:著名的斐波那契数列(Fibonacci),除第一个和第二个数外,任意一个数都可以由前两个数相加得到:1,1,2,3,5,8,13,21,34...用列表生成式写不出来,如何用函数实现?

#方法一:
>>> def fib(max):
...     n,a,b = 0,0,1
...     while n < max:
...             print(b)
...             a,b = b,a+b
...             n += 1
...     return ‘done‘
...
>>> fib(6)
1
1
2
3
5
8
‘done‘

#注:a,b = b,a+b  相当于 t = (b,a+b)  a = t[0]  b = t[1]
#方法二:生成器
>>> def fib(max):
...     n,a,b = 0,0,1
...     while n < max:
...             yield b
...             a,b = b,a+b
...             n += 1
...     return ‘done‘
...
>>> f = fib(6)
>>> f
<generator object fib at 0x00000173FFBFA1A8>
>>> for i in f:
...     print(i)
...
1
1
2
3
5
8

  最难以理解的就是生成器与函数的执行流程不一样。函数是顺序执行,遇到 return 语句或者最后一行函数语句就返回。而变成生成器的函数,在每次调用 next() 的时候执行,遇到 yield 语句返回,再次执行时从上次返回的 yield 语句处继续执行。

#生成器函数每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

>>> def odd():
...     print(‘第一步‘)
...     yield 100
...     print(‘第二步‘)
...     yield 200
...     print(‘第三步‘)
...     yield 300
...
>>> g = odd()
>>> next(g)
第一步
100
>>> next(g)
第二步
200
>>> next(g)
第三步
300
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

#odd()生成器函数,在执行过程中遇到yield就中断,下次继续执行。执行3次yield后,已经没有yield可以执行,所以第4次调用报错。

生成器总结:

a、在Python中可以简单地把列表生成式改为generator,也可以通过函数实现复杂逻辑的generator。生成器的工作原理是在for循环过程中不断计算出下一个元素,并在适当条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

b、普通函数和生成器函数区别:普通函数调用直接返回结果,而生成器函数的“调用”实际返回一个生成器对象

#普通函数
>>> r = abs(-1)
>>> r
1

#生成器函数
>>> g = fib(6)
>>> g
<generator object fib at 0x00000173FFBFA1A8>

三、迭代器
       可以直接作用于 for 循环的数据类型有以下几种:

一类是集合数据类型,如list、tuple、dict、set、str 等;

一类是generator,包括生成器和带 yield 的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以使用isinstance()判断一个对象是否是Iterable对象:

#判断一个对象是否是可迭代对象Iterable
>>> from collections import Iterable
>>> isinstance([],Iterable)
True
>>> isinstance((),Iterable)
True
>>> isinstance({},Iterable)
True
>>> isinstance(‘aaa‘,Iterable)
True
>>> isinstance((x for x in range(5)),Iterable)
True
>>> isinstance(100,Iterable)
False
>>> isinstance(True,Iterable)
False

可以被 next() 函数调用并不断返回下一个值的对象称为迭代器:Iterator。可以使用isinstance()判断一个对象是否是Iterator对象:

#判断一个对象是否是迭代器:Iterator
>>> from collections import Iterator
>>> isinstance([],Iterator)
False
>>> isinstance((),Iterator)
False
>>> isinstance({},Iterator)
False
>>> isinstance(‘aaa‘,Iterator)
False
>>> isinstance((x for x in range(5)),Iterator)
True

可以发现生成器都是迭代器(Iterator)对象,但list、tuple、dict、str虽然是可迭代对象(Iterable),却不是迭代器(Iterator)。那有没有什么方法可以使list、tuple、dict、str等可迭代对象(Iterable)变成迭代器(Iterator)?  iter() 函数可以做这件事!

#iter()将list、tuple、dict、set、str等可迭代对象变为迭代器
>>> isinstance(iter([]),Iterator)
True
>>> isinstance(iter(()),Iterator)
True
>>> isinstance(iter({}),Iterator)
True
>>> isinstance(iter(‘aaa‘),Iterator)
True

为什么list、dict、str等数据类型不是Iterator?这是因为Python的迭代器(Iterator)对象表示的是一个数据流,迭代器(Iterator)对象可以被next() 函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

迭代器(Iterator)甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

迭代器总结:

a、凡是可作用于 for 循环的对象都是可迭代(Iterable) 类型;

b、凡是可作用于 next() 函数的对象都是 迭代器(Iterator) 类型,它们表示一个惰性计算的序列;

c、集合数据类型如list、dict、str等都是可迭代(Iterable)但不是迭代器(Iterator),不过可以通过iter()函数获得一个迭代器(Iterator)对象。

d、Python的for循环本质上就是通过不断调用next()函数实现的。

for x in [1, 2, 3, 4, 5]:
    pass

实际上完全等价于:

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break

四、迭代器生成器关系

1.对于可迭代对象,可以通过 iter() 函数获得迭代器对象,并且可以被next() 函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。

2.生成器是一种特殊的迭代器,生成器通过生成器函数产生,生成器函数可以通过常规的def语句来定义,但是不用return返回,而是用yield一次返回一个结果。return 与 yield 不同之处在于return返回后,函数会释放,而生成器不会。在直接调用next()方法或者用 for 语句进行下一次迭代时,生成器会从yield 下一句开始执行,直至遇到下一个 yield。

3.迭代器可以多次迭代,而生成器只能迭代一次。

#迭代器:可以多次迭代
>>> g = [x*x for x in range(5)]
>>> g
[0, 1, 4, 9, 16]
>>> for i in g:
...     print(i)
...
0
1
4
9
16
>>> g
[0, 1, 4, 9, 16]
>>> for i in g:
...     print(i)
...
0
1
4
9
16

#生成器:只能迭代一次
>>> f = (x*x for x in range(5))
>>> f
<generator object <genexpr> at 0x0000022BA065F0F8>
>>> for i in f:
...     print(i)
...
0
1
4
9
16
>>> f
<generator object <genexpr> at 0x0000022BA065F0F8>
>>> for i in f:
...     print(i)
...
>>>

原文地址:https://www.cnblogs.com/ceo-python/p/11599631.html

时间: 2024-10-09 17:35:09

生成器generator和迭代器Iterator的相关文章

Python之生成器(generator)和迭代器(Iterator)

generator 生成器generator:一边循环一边计算的机制. 生成器是一个特殊的程序,可以被用于控制循环的迭代行为.python中的生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,可以使用next()函数和send()函数恢复生成器. 生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用.但是,不同于一般函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这个消耗的内存数量将大大减小.因此,生成器看起来像是一个函数,但是表现得像迭代

ES6中的迭代器(Iterator)和生成器(Generator)

前面的话 用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,而在许多编程语言中,已经开始通过程序化的方式用迭代器对象返回迭代过程中集合的每一个元素 迭代器的使用可以极大地简化数据操作,于是ES6也向JS中添加了这个迭代器特性.新的数组方法和新的集合类型(如Set集合与Map集合)都依赖迭代器的实现,这个新特性对于高效的数据处理而言是不可或缺的,在语言的其他特性中也都有迭代器的身影:新的for-of循环.展开运算符(...),甚至连异步编程都可以使用迭代器 本文将详细介

ES6中的迭代器(Iterator)和生成器(Generator)(一)

用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,而在许多编程语言中,已经开始通过程序化的方式用迭代器对象返回迭代过程中集合的每一个元素 迭代器的使用可以极大地简化数据操作,于是ES6也向JS中添加了这个迭代器特性.新的数组方法和新的集合类型(如Set集合与Map集合)都依赖迭代器的实现,这个新特性对于高效的数据处理而言是不可或缺的,在语言的其他特性中也都有迭代器的身影:新的for-of循环.展开运算符(...),甚至连异步编程都可以使用迭代器 一.引入 下面是一段标

迭代器,生成器(generator)和Promise的“微妙”关系

需要Promise源码版的朋友:传送链接 本文主要讲述(iterator)和生成器*/yield之间的联系和各自的用法,以及生成器的高配版本aysnc/await的使用. 大纲: 迭代器(iterator) 生成器 */yield 异步版生成器 aysnc/await 迭代器(iterator) 先瞅瞅"迭代",这个词是什么意思呢?每一次"过程"的重复,称之为迭代.不过迭代是会保留结果的,也就说每次都是以上一次迭代的结果为基准,开始下一次的迭代.举个例子,迭代这个词

Python高级编程之生成器(Generator)与coroutine(一):Generator

这是一系列的文章,会从基础开始一步步的介绍Python中的Generator以及coroutine(协程)(主要是介绍coroutine),并且详细的讲述了Python中coroutine的各种高级用法,最后会用coroutine实现一个简单的多任务的操作系统. 其实也是看完这篇文章的学习笔记吧!O(∩_∩)O 生成器(Generator) 什么是生成器?在Python中,生成器(Generator)是一个带有yield关键字的函数 1 def gene(): 2 a = 1 3 print "

生成器generator

生成器generator 定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器 代码: def cash_out(amount): while amount >0: amount -= 1 yield 1<br> print("擦,又来取钱了...败家子!") ATM = cash_out(5) print("取到钱 %s 万" % ATM.__next__())

Python高级编程之生成器(Generator)与coroutine(二):coroutine介绍

原创作品,转载请注明出处:点我 上一篇文章Python高级编程之生成器(Generator)与coroutine(一):Generator中,我们介绍了什么是Generator,以及写了几个使用Generator Function的示例,这一小节,我们会介绍Python的coroutine,以及会有一个小例子,再接下来的文章中会以代码的形式一步步介绍coroutine的高级用法. coroutine(协程) 什么是coroutine?coroutine跟Generator有什么区别?下面先看一段

可迭代对象 Iterable 与 迭代器 Iterator

迭代器 Iterator与可迭代对象  1 常见的可迭代对象: 字符串列表字典集合元组文件句柄 -->> 迭代器range() -->> 只是一个可迭代对象迭代器本身也可迭代 2 判断是否是 可迭代对象 的方法: 1 from collections import Iterable isinstance('abcd',Iterable) 2 可以判断不同方法的差异 dir() 用set集合 有__iter__() 方法 的数据类型 (即 可迭代协议 ------- 数据类型与pyt

python学习--生成器Generator

生成器函数:在函数中如果出现了yield关键字,那么这个函数就是生成器函数,yield的作用就是生成一个generator,生成器函数返回一个生成器. 实现一个generator:1.把列表的[ ]换成(),就创建了一个generator. >>> L = [x * x for x in range(10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x * x for x in range