On the way of Pythonic...
Generator和iterator相伴相生,却不尽相同。
生成器(generator)
generator通常也是可迭代的,但并非是一次性生成所有迭代成员的列表,而是在循环的过程中通过next()方法不断获取后续元素。所以generator的存在可以节省内存资源(假如需要迭代一个包含海量数据的列表,那所占用的内存也会是不可忽略的)
下面的代码就可以获得一个generator:
from types import GeneratorType
from collections import Iterable, Iterator
g = (x for x in range(10))
print(isinstance(g, GeneratorType))
print(isinstance(g, Iterable))
print(isinstance(g, Iterator))
>>>
True
True
True
我们也可以自己定义一个generator,当然这就要用到yield关键字
from types import GeneratorType
from collections import Iterable, Iterator
def fib(max):
a, b = 0, 1
while True:
if b > max:
return
else:
yield b
a, b = b, a+b
print(a, b)
print(isinstance(fib(5), GeneratorType))
print(isinstance(fib(5), Iterable))
print(isinstance(fib(5), Iterator))
for f in fib(5):
print f
>>>
True
True
True
1
(1, 1)
1
(1, 2)
2
(2, 3)
3
(3, 5)
5
(5, 8)
- fib(5)就是一个generator, 同样也是一个iterator,所以支持用for来进行迭代。
- yield和return同样都返回函数的值,区别在于return的返回是一次性的。yield只是返回了generator的一次迭代值, 函数的代码在yield返回迭代值后就会停止本次执行,yield之后以及之前的代码都只会在下次迭代执行。
- generator在迭代完所有的值后,再次迭代(执行next()方法)会自动抛出StopIteration异常。但在for循环中无需处理该异常, 循环能够正常结束。
迭代器(iterator)
可以通过next()方法不断调用下一个迭代值的对象成为迭代器,迭代器支持for循环进行迭代。
- 可迭代(Iterable)的数据类型包括,list, tuple, dict, set, str等,但这些数据类型并不是Iterator
- Generator同样也是一个iterator,并且也是一种Iterable的数据类型
from types import GeneratorType
from collections import Iterable, Iterator
print(isinstance([], GeneratorType))
print(isinstance([], Iterable))
print(isinstance([], Iterator))
print(isinstance(iter([]), Iterator))
>>>
False
True
False
True
- 如果有必要,可以使用iter()函数将Iterabe的对象转换成Iterator对象。
To be continue...