generator是一种函数或表达式,它返回一种特殊的迭代器,叫做生成器迭代器。
Generator-iterators是惰性的:它们不把values存储在内存中,而是在需要时才_生成_这些值。
生成器函数看起来和其他函数没什么两样,只是其中包含一个或多个yield表达式。
每个yield都会暂停代码执行,并保存当前的执行状态(包括所有局部变量和 try 语句)。
生成器恢复执行时,会从暂停处继续,沿用当时的状态,而普通函数每次调用都会重置。
生成器的构造方式和其他循环或递归函数很像,但它需要一个yield表达式,我们稍后会更深入地探讨它。
举个例子,下面这个函数会返回给定数组中各数字的_平方_。 按现在的写法,必须先处理完所有输入,才能返回任何值:
>>> def squares(list_of_numbers):
... squares = []
... for number in list_of_numbers:
... squares.append(number ** 2)
... return squares
你可以像这样把它改写成生成器:
>>> def squares_generator(list_of_numbers):
... for number in list_of_numbers:
... yield number ** 2
这么做的道理在于:当你不需要_一次性_拿到所有值时,就该用生成器。
这样可以节省内存和运算开销,因为只计算你_当前正在处理_的那个值。
生成器(严格来说是generator-iterator,见下面的提示)是iterator的一种,在 Python 中任何需要iterator或iterable的地方都能使用。
这也包括那些需要iterable或iterator作为实参的_函数_或_对象_。
想深入了解的话,可以看看 How to Make an Iterator in Python。
生成器迭代器是迭代器的一个特殊子集。
所谓Iterators,就是让_可迭代对象_能够被循环遍历的机制/协议。
生成器迭代器与常见 Python iterables返回的迭代器行为非常相似,但有几个重要区别需要注意:
indexes。
你无法通过加法或减法引用之前或之后的值,也不能使用方括号([])表示法或切片。len()函数一起使用。generator-iterator中收集所有值时要小心!要使用squares_generator()生成器:
>>> squared_numbers = squares_generator([1, 2, 3, 4])
>>> for square in squared_numbers:
... print(square)
...
1
4
9
16
生成器中的值也可以通过next()函数来产生或获取。
next()会调用生成器对象的__next__()方法,把生成器代码“推进”或执行到它的yield表达式,该表达式随即“产出”或返回这个值。
>>> squared_numbers = squares_generator([1, 2])
>>> next(squared_numbers)
1
>>> next(squared_numbers)
4
当一个generator被完全耗尽、没有更多值可返回时,它会抛出StopIteration错误。
>>> next(squared_numbers)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
生成器是_迭代器_的一个特殊子集。
所谓Iterators,就是让_可迭代对象_能够被循环遍历的机制/协议。
生成器和常见 Python iterables返回的迭代器行为非常相似,但有几个重要区别需要注意:
生成器是_单向_的,无法“回退”到之前的值。
遍历生成器会消耗返回的值,无法重置。
生成器(因为采用惰性求值)不能排序,也不能反转。
生成器_没有_indexes,所以不能通过加法或减法引用之前或之后的值。
生成器不能与len()函数一起使用。
生成器可以是_有限_的,也可以是_无限_的,从_无限_生成器中收集所有值时要小心。
yield 表达式与return表达式非常相似。
与return表达式_不同_,yield会在_特定的位置_把值交给调用方,并暂停对其余任何值的求值或返回,直到这些值被请求为止。
当yield被求值时,它会暂停所在函数的执行,并返回该函数_在那一刻_的值。
之后函数会_保持在作用域内_,当__next__()被调用时,执行继续进行,直到再次遇到yield为止。
yield表达式不能在函数之外使用。
>>> def infinite_sequence():
... current_number = 0
... while True:
... yield current_number
... current_number += 1
>>> lets_try = infinite_sequence()
>>> lets_try.__next__()
0
>>> lets_try.__next__()
1
生成器在许多场景中都很实用。
处理大型集合时,你可能不想把它的所有值都放进memory。
生成器可以一点一点地处理更大的数据,从而节省内存并提升性能。
当某个过程或计算_复杂_、_昂贵_或_无限_时,生成器也非常有用:
>>> def infinite_sequence():
... current_number = 0
... while True:
... yield current_number
... current_number += 1
这样一来,只要对infinite_sequence对象调用__next__(),它就会返回_前一个数字_加 1。