Python的生成器和迭代器

1. 生成器 Generator

前面有列表解析式,集合解析式,字典解析式,唯独没有元组解析式,这是因为元组的小括号 ( ) ,被用来做生成器了。

1.1 生成器表达式 Generator Expression

( 返回值 for 元素 in 可迭代对象 if 条件 )

通过生成器表达式,我们就创建了一个生成器,所说的生成器,就是不断地生产出我们需要的数据。

但是要注意,生成器里面储存的是所需数据的算法,而不是数据:

g = (i for i in range(5))
g
<generator object <genexpr> at 0x00000214B0EFFE08>
#生成器对象,genexpr里面是generator expression的缩写,后面at是指出存在哪里

1.2 判断是否是生成器或迭代器

用isinstance()来判断,需要注意得是,需要先import相应的类方法。
返回bool值。

from collections import Generator
isinstance((i for i in range(5)),Generator)
True

from collections import Iterator
isinstance(iter(range(5)),Iterator)
True

1.3 用生成器获取数据

如果需要生成器计算出一个数据并返回,需要手动操作并返回,此时需要一个next()函数。

next(g)
0

next(g)
1

....

next(g)
4

next(g)
#会报错,StopIteration 

我们创建的这个生成器g,只能使用5次,之后再使用就会报错stopiteration,就是说迭代停止了,这说明什么?
说明一个生成器只能依次生产数据,如果内部算法可以得出的数据都生产完了,那么这个生成器就结束了他的使命,要想再次使用,得重新定义,也就是重新做一个生成器。

如果需要生成器生成全部的数据,需要用for循环来迭代,因为生成器都是迭代器iterator,但是一定要注意,迭代器不一定是生成器。

g = (i for i in range(5))

for i in g:
    print(i) 
    #迭代一遍这个生成器,此时它作为一个迭代器,行驶的是迭代器的功能,打印生产出的数据。
print('........................') #分隔一下
for i in g:
    print(i+1) #想再迭代一遍这个生成器(迭代器),打印i+1

0
1
2
3
4
........................

可以看出,这个生成器只能使用一次,一旦算法没有数据可以生产了,就停止。

1.4 生成器的特性

可以看到, 生成器和列表的区别只在于,一个用的是 ( ) ,一个用的是 [ ] ,不过对比一下更能理解生成器。

[i**2 for i in ragne(3)]
(i**2 for i in ragne(3))

列表解析式,立刻生成了一个列表,列表内存有数据,储存在内存中,用就直接提取。
生成器,只是做了一个储存了数据的算法的容器,没有数据,要用数据的时候再算,这叫做惰性求值,也叫延迟计算。

列表内存有已经算好的数据,所以占了很大空间。
生成器里没有数据,只有数据的算法,所以占用的内存空间少,但是如果数据全部算出来,占用的内存空间也差不多。

如果数据规模小,适合用列表。
如果数据规模大,十分占内存空间,适合用生成器,然后再计算出数据。

2. 迭代器

2.1 可迭代对象

首先要明白什么是可迭代对象。
可迭代对象里面有很多“不同”的元素,然后能通过一次次迭代把这些“不同”的元素依次取出来。这个“不同”指的是不是同一个元素,比如一个tuple(1, 1, 2),是可迭代对象,其中有两个元素的值都为1,但这两个元素是不同的元素。

常见的可迭代对象有list,tuple,str,bytes,bytearray,range(),set,dict。可以看出,无论这个可迭代对象可以有序,可以无序。

可迭代对象可以用in,not in这种身份运算符,看某个元素是否在这个可迭代对象里面。

是不是可迭代对象可以用collections模块下的iterable和isinstance来判断:

from collections import Iterable
isinstance(100,Iterable)
False

2.2 迭代器

具备可迭代对象的特征,可以迭代出一个个元素。

可以通过iter(iterable)来把一个可迭代对象封装成迭代器,封装成迭代器之后,就可以要一个数据,出一个数据。

i = iter(range(3))
next(i)
0

next(i)
1

next(i)
2

生成器对象也是一个可迭代对象。

zip(*iterable)

zip n.拉链

这个拉链函数,括号内可以写多个iterable,功能就是,把这些iterable的元素都一一对应起来,构成一个个元组,然后把这个元组迭代出来。

zip([1,2,3],['a','b','c'],['A','B','C'])
<zip at 0x21e976c8508>

list(_) # _是调取上一次输出的内容
[(1, 'a', 'A'), (2, 'b', 'B'), (3, 'c', 'C')]

这个zip()函数,和字典解析式是天造地设的一对:

{str(i):j for i,j in zip('abcd', range(4))}
{'a': 0, 'b': 1, 'c': 2, 'd': 3}

dict(zip(range(5), 'ABCDE'))
{0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E'}

能直接把key和value对应起来,不用循环,牛逼坏了

猜你喜欢

转载自blog.csdn.net/LittleHuang950620/article/details/81808538