IOTXING

记录技术学习之路

0%

举例讲解python生成器与迭代器

python有几个比较重要的概念,生成器,装饰器,迭代器,其中生成器跟迭代器很容易弄混淆。 下面已几个例子来进行区分生成器和迭代器

list = [1,2,3,4,5,6,7,8,9,10]
for i in list:
    print i 

我们在这里使用了for循环,来将list中的元素一一的打印出来,此时list称为可迭代对象,而不是迭代器 因为如果我们查看list的type的时候,系统会提示如下

In [1]: a = [1,2,3,4,5]

In \[2\]: type(a)
Out\[2\]: list

In \[3\]: a.next()
---------------------------------------------------------------------------

AttributeError: 'list' object has no attribute 'next'

可迭代对象是一种实现了迭代器协议的对象 可以直接使用for循环的对象都是可迭代对象

生成器 我们首先来做一个测试,使用不同的方法来计算0到1亿里面所有值的和,通过对比时间来比较性能

1- sum( i for i in range(100000000))
2- sum( [i for i in range(100000000)])

经过测试,所耗时分别如下:

1- 耗时8.6s,占用内存1.5g
2- 报错,内存溢出,占用超过1.6g
 这说明第二种不管从内存占用还是耗时方面来讲,都比第一种要占用给多的资源以及时间 我们换一种写法再来看看上面的内容 


1- def add():
        for i in range(100000000):
            yield i
    sum(add())

2- def add():
        list = []
        for i in range(100000000):
            list.append(i)
    sum(add())

这和上面实现的其实是同一种效果,只是采用了不同的书写方式。 下面我们来看第一种方式,里面使用了yield关键字,因此第一种的add方法其实也就是所谓的生成器,在sum的时候,add方法里面的for才开始运行。在运行的时候,一次只会产生一个结果

>>; x = add()
>>>; x
<generator object add at 0x04BD7A30>
>>; next(x)
0
>>>; next(x)
1
>>>; next(x)
2
>>>; next(x)
3
>>>; next(x)
4
>>>; 

可以看到x的类型是generator类型,也就是生成器,x一次只有一个值,使用next函数可以获取到x的下一个值 再来看看第二种方法的结果

>>>; x = add()
>>>; x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>>;

x在打印的时候,直接把所有的结果打印出来了,也就是说在打印之前,x已经完成了函数里面的全部运算。 我个人对这两种的方法理解可以用洗车来比喻: 洗车的步骤是洗车然后冲干,第一种方式是洗一辆冲一辆,第二种方法是先把所有的车都洗完,然后再把所有的车都冲干净,很明显的会感觉第二种消耗资源会比较多 每个生成器只能被使用一次,不能够复用,例如下面

>>>; def add():
...     for i in range(1000):
...         yield i
...
>>> x = add()
>>> print sum(x)
499500
>>> print sum(x)
0
>>>

x里面的内容已经被遍历过一次了,因此第二次打印的时候并不会打印出来数据 如果想再次打印,则需要再生成一个生成器 从这里我们可以看出来,生成器是一种返回迭代器的函数