我们可以通过生成列表来创建,但是由于内存是有限的与之对应的列表容器也是有限的。 假如要创建100万个元素的列表。 实际上只需要前几个元素。 那么多余的元素就会浪费大量的空间。 所以可以根据一定的规则可以在循环过程中推选出后续的元素。是、这种一边循环一遍计算的机制称之为生成器(generator)
把一个列表生成器[]改成(), 从而创建一个generator
a = [x * 2 for x in range(10)]
print(a)
b = (x * 2 for x in range(10))
print(b)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
at 0x10b1fd650>
示例的区别在于a最外层是[]. 而b最外层是(),而且在输出结果上也有明显的差别。我们知道列表中的元素可以一一打印出来。 而generator则需要借助next()函数才能打印出结果。
b = (x * 2 for x in range(10))
print(b)
print(next(b))
print(next(b))
print(next(b))
print(next(b))
print(next(b))
print(next(b))
print(next(b))
print(next(b))
print(next(b))
print(next(b))
print(next(b))
0
2
4
6
8
10
12
14
16
18
Traceback (most recent call last):
File "/Users/apple/Documents/重要文件/python3/python21.py", line 14, in
print(next(b))
StopIteration
因为generator保存的是算法。所以每次调用next()时都会计算出下一个元素。直至计算完最后一个元素在无可计算的元素时回抛出异常。当然访问generator的正确方法是通过循环。通过一次次手写调用next()访问显然不是明智之举。
b = (x * 2 for x in range(10))
print(b)
for i in b:
print(i)
at 0x10e5ec550>
0
2
4
6
8
10
12
14
16
18
这种访问访问方式即使访问到最后一个元素也不会抛出异常。 如果算法比较复杂。 无法用for生成还可以用函数生成。
def fib(max):
n, a, b = 0, 1, 2
while n < max:
print(b)
a, b = b, a + b
n += 1
fib(10)
2
3
5
8
13
21
34
55
89
144
上面的函数生成一个斐波拉契数列。 这里只是一个算法但是把他稍微改造一下就成了generator。
def fib(max):
n, a, b = 0, 1, 2
while n < max:
yield b
a, b = b, a + b
n += 1
a = fib(10)
print(a)
经过改造一个普通函数已经变成了generator。 也就意味着一个函数中只要出现了yield这个关键字他就不是普通的函数了。而是一个generator,还有一点必须要注意的是generator和普通的函数在执行流程上是有所区别的 ,普通的函数是顺序执行的。 遇到return回返回。 而generator在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。要访问上述示例中的元素最简单的还是使用循环。
def fib(max):
n, a, b = 0, 1, 2
while n < max:
yield b
a, b = b, a + b
n += 1
a = fib(10)
print(a)
for i in a:
print(i)
2
3
5
8
13
21
34
55
89
144
通过for能遍历的一般有两种类型的数据 :一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;另一类是generator
,包括生成器和带yield
的generator function。这些可以直接作用于for
循环的对象统称为可迭代对象:Iterable
isinstance()
判断一个对象是否是Iterable
对象:from collections.abc import Iterable
a = isinstance([1, 2], Iterable)
print(a)
b = isinstance(12, Iterable)
print(b)
True
False
而生成器不但可以作用于for
循环,还可以被next()
函数不断调用并返回下一个值,直到最后抛出StopIteration
错误表示无法继续返回下一个值了。可以被next()
函数调用并不断返回下一个值的对象称为迭代器:Iterator
。
可以使用isinstance()
判断一个对象是否是Iterator
对象:
from collections.abc import Iterator
a = 'python'
print(isinstance(a, Iterator))
b = (x for x in range(10))
print(isinstance(b, Iterator))
False
True
生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。可以使用iter()()函数将Iterable变成的Iterator,
from collections.abc import Iterator
a = 'python'
print(isinstance(iter(a), Iterator))
True