Python学习:生成器(generator)和迭代器(iterator)
生成器generator
通过列表生成式可以直接创建列表,但是受到内存限制,列表容量肯定是有限的。而且创建一个包含100万个元素的列表,不仅占用大量内存,如果我们仅仅需要访问其中某几个元素,那么绝大多数空间是浪费了。
所以,如果列表是按照某种算法推算出来的,那么我们可以在循环过程中推算出后面的所有元素。这样就不必创建完整的 list了,从而节省了大量的存储空间。在Python中,一边循环一边计算的机制,成为生成器generator。
要创建一个generator有很多种方法。第一种方法很简单,就是把列表生成式[]改成(),就创建了一个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(10))
>>>g
<generator object <genexpr> at 0x10e357a00>
那要怎么全部打印出来呢?用内置函数next()
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):File "<stdin>", line 1, in <module>StopIteration
generator保存的是算法,每次调用next(g),就计算出下一个值,知道计算到最后一个元素,没有更多元素时,抛出StopIteration的错误。
当然,上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:
>>> g = (x * x for x in range(10))
>>> for n in g:
... print(n)
...
斐波拉切数列用列表生成式写不出来,但是用代码写出来很容易:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a+b
n = n+1
return 'Done'
注意赋值语句:
a, b = b, a+b
相当于:
t = (b, a + b) # t是一个tuple
a = t[0]
b = t[1]
但是不必显式的声明临时变量t。
从上面可以看出,列表是按照斐波拉切算法推导出来的,这和生成器generator很相似。
只需要把上面代码print(b)改成yield b.
函数中有关键字yield就和普通的函数不一样了。普通函数流程是顺序执行到结束返回。而含有yield的函数,每次调用next()的时候执行,遇到yield返回,再次执行的时候从上次yield语句处继续执行。
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a+b
n = n+1
print(f)
#运行结果为<generator object fib at 0x10fe6fa50>
f = fib(10)
for n in f:
print n
例子:杨辉三角
迭代器iterator
我们知道,可以用for()循环的有以下几种:
第一种是集合数据类型如list,tuple,dic,set,str等;
第二种是生成器generator,包括带有yield的函数。
这些能使用for循环的对象统称为可迭代对象Iterable。
可以使用isinstance()来判断一个对象是否是可迭代对象。
>>>from collections import Iterable
>>>isinstance([], Iterable)
True
>>>isinstance((x*x for x in range(10)), Iterable)
True
>>>isinstance(100, Iterable)
False
而生成器不但可以用于for循环,还可以被next()函数调用并且返回下一个值,直到最后抛出StopIteration错误,表示无法继续返回下一个值了。
可以被next()调用,并且可以不断返回下一个值的对象,被成为迭代器Iterator。
可以使用isinstance()判断对象是否是迭代器Iterator。
>>>from collections import Iterator
>>>isinstance((x*x for x in range(10)), Iterator)
True
>>>isinstance([], Iterator)
False
>>> isinstance('abc', Iterator)
False
>>> isinstance(iter([]), Iterator)
True
生成器都是迭代器Iterator,但是可迭代对象Iterable不一定都是生成器Iterator,比如list
、dict
、str
都不是迭代器Iterator。把list
、dict
、str
等Iterable变成迭代器Iterator可以用内置函数iter()。
为什么list
、dict
、str
等Iterable内置数据类型不是迭代器Iterator?因为Python的迭代器Iterator表示的是一个数据流。Iterator对象可以被next函数调用,并不断返回下一个数据,并直到没有数据时候抛出StopIteration错误。可以把这个数据流看作有序序列,但是我们却不能提前知道序列的长度,只能通过next()函数计算出下一个数据,这种Iterator计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限长度的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
小结:
可以用for循环的都是可迭代对象Iterable;
generator
和list
、dict
、str
等对象都可以用for循环,即可迭代对象Iterable;
数据集合list
、dict
、str
等是循环的都是可迭代对象Iterable;,但不是迭代器Iterator。
转载于:https://blog.51cto.com/12877417/1924721
上一篇: Jlabel实现内容自动换行简单实例
下一篇: PHP中的PDO详解
推荐阅读
-
python生成器generator和迭代器Iterator测试
-
python 生成器generator和迭代器Iterator
-
Python学习:生成器(generator)和迭代器(iterator)
-
Python 迭代器(iterator)和生成器(generator)
-
ES的迭代器Iterator和生成器Generator
-
Python的iterator和generator(迭代器与生成器)相关概念简述
-
详解Python中的生成器和迭代器(generator和iterator)
-
ES6 迭代器(Iterator)和 for.of循环使用方法学习(总结)
-
python面试题之迭代器和生成器的区别
-
Python学习之路---Python迭代器与生成器