生成器 (计算机编程)

生成器（Generator），是计算机科学中特殊的子程序。实际上，所有生成器都是迭代器。生成器非常类似于返回数组的函数，都是具有参数、可被调用、产生一系列的值。但是生成器不是构造出数组包含所有的值并一次性返回，而是每次产生一个值，因此生成器看起来像函数，但行为像迭代器。 
生成器可以用更有表达力的控制流结构实现，如协程或头等续体。生成器，也被称作半协程（semicoroutine），是特殊的、能力更弱的协程，总是在传回一个值时把控制交还给调用者，而不是像协程那样指出另一个协程继续执行。
使用.
生成器通常在一个循环内部被调用。生成器第一次被调用是在进入这个循环结构时，创建一个对象以封装生成器的状态、绑定的实参。生成器的实体接着被执行直至遇到一个特别的codice_1动作，在这里提供给codice_1动作的值被返回给调用者。在下一次调用同一个生成器的时候，生成器从codice_1动作之后恢复执行，直到遇上另一个codice_1动作。生成器的执行也可以遇到codice_5动作而终止。
由于生成器在需要的才计算它的要被codice_1的值，因此可以用来代表一个串流，这种序列要一次性全部计算出来是昂贵的甚至是不可能的，这种情况还包括无穷序列或现场数据串流。 
如果需要及早求值（主要是在序列是有限的时候，否则求值将永不终止），可以使用列表或使用并行结构来创建一个列表替代生成器。例如，Python的一个生成器codice_7，通过codice_8，可被求值成列表codice_9。而在F♯中，序列表达式codice_10，将除了codice_11之外的惰性的（生成器或序列）求值为及早的（列表）。
在有生成器出现的情况下，语言的循环构造，比如codice_12和codice_13，可以归约成一个单一的codice_14构造；可以用合适的生成器以正确的方式，顺畅的模拟所有常见的循环构造。例如，一个按范围的循环如codice_15，可以通过生成器而被实现为迭代，比如Python的codice_16。进一步的，codice_17可以被实现为向生成器发送codice_5，而接着在循环中使用codice_19。
历史.
生成器最早出现于CLU语言（1975年），也是字符串操纵语言Icon（1977年）的显著特征。它现在出现在Python、C♯、Ruby、最新版本的ECMAScript（ES6/ES2015）与其他语言之中。在CLU与C#中，生成器称作迭代器，在Ruby称作枚举器。
语言实例.
CLU.
CLU使用codice_1语句来在用户定义数据抽象上进行迭代：
<syntaxhighlight lang="ada">
string_chars = iter (s: string) yields (char);
end string_chars;
for c: char in string_chars(s) do
end;
</syntaxhighlight>
Icon.
在Icon中，所有表达式（包括循环）都是生成器。语言有很多内建生成器，甚至使用生成器机制实现某些逻辑语义（逻辑析取或codice_21以此达成）。
打印从codice_22到codice_23的平方，可以如下这样使用协程完成：
<syntaxhighlight lang="icon">
</syntaxhighlight>
但是多数时候，定制生成器是使用codice_24关键字来实现，它的功能完全类似CLU中的codice_1关键字。
C++.
使用宏预处理的例子见:
<syntaxhighlight lang="cpp">
$generator(descent)
</syntaxhighlight>
可迭代：
<syntaxhighlight lang="cpp">
int main(int argc, char* argv[])
</syntaxhighlight>
C++11提供的foreach loop可用于任何具有codice_26与codice_27成员函数的类。还需要有codice_28, codice_29 与codice_30。例如：
<syntaxhighlight lang="cpp">
int main()
一个基本实现：
<syntaxhighlight lang="cpp">
class range
private:
public:
</syntaxhighlight>
C♯.
C♯ 2.0开始可以利用codice_1构造生成器。
<syntaxhighlight lang="csharp">
// Method that takes an iterable input (possibly an array)
// and returns all even numbers.
public static IEnumerable<int> GetEven(IEnumerable<int> numbers) {
</syntaxhighlight>
可以使用多个codice_32语句： 
<syntaxhighlight lang="csharp">
public class CityCollection : IEnumerable<string> {
</syntaxhighlight>
Python.
Python自2001年的2.2版开始支持生成器。下面是生成器一个例子，它是个计数器：
<syntaxhighlight lang="python">
def countfrom(n):
for i in countfrom(10):
</syntaxhighlight>
另一个生成器例子，它按需要无尽的产生素数：
<syntaxhighlight lang="python">
import itertools
def primes():
</syntaxhighlight>
Python的生成器可以认为是一个迭代器包含了冻结的栈帧。当用codice_33方法调用迭代器，Python恢复冻结的栈帧，继续执行至下一次的codice_1语句。生成器的栈帧再一次冻结，被yield的值返回给调用者。 
PEP 380 (Python 3.3开始)增加了codice_35表达式，允许生成器将它的一部份操作委托给另一个生成器。
生成器表达式.
Python拥有建模于列表推导式的一种语法，叫做生成器表达式，用来辅助生成器的创建。下面的例子扩展了上面第一个例子，使用生成器表达式来计算来自codice_36生成器函数的数的平方：
<syntaxhighlight lang="python">
squares = (n*n for n in countfrom(2))
for j in squares:
</syntaxhighlight>
Smalltalk.
下面例子使用Pharo Smalltalk，黄金分割率生成器对codice_37调用，每次返回一个更加逼近的黄金分割率： 
<syntaxhighlight lang="Smalltalk">
goldenRatio := Generator on: [ :g |
 x := 0.
 y := 1.
 z := x + y.
 r := (z / y) asFloat.
 x := y.
 y := z.
 g yield: r
 ] repeat 
goldenRatio next.
</syntaxhighlight>
下面的表达式返回的下次codice_38个逼近。
<syntaxhighlight lang="Smalltalk">
(1 to: 10) collect: [ :dummy | goldenRatio next].
</syntaxhighlight>