我们知道用列表生成式可以很方便快捷地生成list,但是,如果我们需要生成的list很长的话,就会比较占内存空间。于是,Python提供了一种动态生成list的机制,能够在你需要这个元素的时候才来计算这个元素的值,这种机制叫做生成器(generator)。我们来先看一个简单的例子:
llist1 = [x for x in range(100) if x%3==0] #这是用列表生成式生成一个list
list2 = (x for x in range(100) if x%3==0) #这是用生成器生成一个list
print("list1: ", list1)
print("list2: ", list2)
运行结果:list1: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99]
list2: <generator object <genexpr> at 0x0000000002A1FEB8>
从上述例子中我们可以看到,用生成器生成list的代码和用列表生成式的很相似,最大的区别就在于列表生成式用的是[],而生成器用的是()。从运行结果来看,列表生成式是一次性把所有的元素都算出来然后存在内存中,而list2则没有进行任何计算。那么问题来了,我们要怎么去访问list2中元素的值呢?有两种方式,第一种是使用next()方法;第二种是通过循环,下面分别做两个例子:
list2 = (x for x in range(100) if x%3==0)
print(next(list2), next(list2), next(list2)) #结果是:0,3,6
for l in list2:
print(l)
#结果是:0,3,6,9,...
生成器比列表生成式更强大的一个地方在于如果生成list中元素的算法比较复杂,通过简单的循环无法实现的时候,生成器支持通过函数来实现。比如我们现在写一个打印上面那个list的函数:
def printList():
for i in range(100):
if i%3==0:
print(i)
return 'finished'
printList()
生成器要利用这个函数来生成list的话只需要把上面的print(i)这条语句改成yield i。
def printList():
for i in range(100):
if i%3==0:
yield i
return 'finished'
list = (printList())
for l in list:
print(l)
接下来再看一个更复杂一点的例子:生成杨辉三角。
def yhtriangle(n):
L=[1]
for i in range(n):
yield L
L=[1] + [L[j] + L[j+1] for j in range( len(L)-1 )] + [1]
return L
list = (yhtriangle(5))
for l in list:
print(l)
运行结果:
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]