fbpx
维基百科

生成器 (计算机编程)

生成器(Generator),是计算机科学中特殊的子程序。实际上,所有生成器都是迭代器[1]。生成器非常类似于返回数组的函数,都是具有参数、可被调用、产生一系列的值。但是生成器不是构造出数组包含所有的值并一次性返回,而是每次产生一个值,因此生成器看起来像函数,但行为像迭代器。

生成器可以用更有表达力的控制流结构实现,如协程或头等計算續體[2]。生成器,也被称作半协程(semicoroutine)[3],是特殊的、能力更弱的协程,总是在传回一个值时把控制交还给调用者,而不是像协程那样指出另一个协程继续执行。

使用 编辑

生成器通常在一个循环内部被调用。[4] 生成器第一次被调用是在进入这个循环结构时,创建一个对象以封装生成器的状态、绑定的实参。生成器的实体接着被执行直至遇到一个特别的yield动作,在这里提供给yield动作的值被返回给调用者。在下一次调用同一个生成器的时候,生成器从yield动作之后恢复执行,直到遇上另一个yield动作。生成器的执行也可以遇到finish动作而终止。

由于生成器在需要的才计算它的要被yield的值,因此可以用来代表一个串流,这种序列要一次性全部计算出来是昂贵的甚至是不可能的,这种情况还包括无穷序列或现场数据串流。

如果需要及早求值(主要是在序列是有限的时候,否则求值将永不终止),可以使用列表或使用并行结构来创建一个列表替代生成器。例如,Python的一个生成器g,通过l = list(g),可被求值成列表l。而在F#中,序列表达式seq { ... },将除了[ ... ]之外的惰性的(生成器或序列)求值为及早的(列表)。

在有生成器出现的情况下,语言的循环构造,比如forwhile,可以归约成一个单一的loop ... end loop构造;可以用合适的生成器以正确的方式,顺畅的模拟所有常见的循环构造。例如,一个按范围的循环如for x = 1 to 10,可以通过生成器而被实现为迭代,比如Python的for x in range(1, 10)。进一步的,break可以被实现为向生成器发送finish,而接着在循环中使用continue

历史 编辑

生成器最早出现于CLU语言(1975年)[5],也是字符串操纵语言Icon(1977年)的显著特征。它现在出现在Python[6]C#[7]Ruby、最新版本的ECMAScript(ES6/ES2015)与其他语言之中。在CLU与C#中,生成器称作迭代器,在Ruby称作枚举器。

语言实例 编辑

CLU 编辑

CLU使用yield语句来在用户定义数据抽象上进行迭代[8]

string_chars = iter (s: string) yields (char); index: int := 1; limit: int := string$size (s); while index <= limit do yield (string$fetch(s, index)); index := index + 1; end; end string_chars; for c: char in string_chars(s) do ... end; 

Icon 编辑

Icon中,所有表达式(包括循环)都是生成器。语言有很多内建生成器,甚至使用生成器机制实现某些逻辑语义(逻辑析取OR以此达成)。

打印从020的平方,可以如下这样使用协程完成:

 local squares, j squares := create (seq(0) ^ 2) every j := |@squares do if j <= 20 then write(j) else break 

但是多数时候,定制生成器是使用suspend关键字来实现,它的功能完全类似CLU中的yield关键字。

C++ 编辑

使用宏预处理的例子见[9]:

$generator(descent) {  // place for all variables used in the generator  int i; // our counter  // place the constructor of our generator, e.g.   // descent(int minv, int maxv) {...}    // from $emit to $stop is a body of our generator:    $emit(int) // will emit int values. Start of body of the generator.  for (i = 10; i > 0; --i)  $yield(i); // a.k.a. yield in Python,  // returns next number in [1..10], reversed.  $stop; // stop, end of sequence. End of body of the generator. }; 

可迭代:

int main(int argc, char* argv[]) {  descent gen;  for(int n; gen(n);) // "get next" generator invocation  printf("next number is %d\n", n);  return 0; } 

C++11提供的foreach loop可用于任何具有beginend成员函数的类。还需要有operator!=, operator++operator*。例如:

#include <iostream> int main() {  for (int i: range(10))  {  std::cout << i << std::endl;  }  return 0; } 

一个基本实现:

class range { private:  int last;  int iter; public:  range(int end):  last(end),  iter(0)  {}  // Iterable functions  const range& begin() const { return *this; }  const range& end() const { return *this; }  // Iterator functions  bool operator!=(const range&) const { return iter < last; }  void operator++() { ++iter; }  int operator*() const { return iter; } }; 

C# 编辑

C# 2.0开始可以利用yield构造生成器。

// Method that takes an iterable input (possibly an array) // and returns all even numbers. public static IEnumerable<int> GetEven(IEnumerable<int> numbers) {  foreach (int i in numbers) {  if ((i % 2) == 0) {  yield return i;  }  } } 

可以使用多个yield return语句:

public class CityCollection : IEnumerable<string> {  public IEnumerator<string> GetEnumerator() {  yield return "New York";  yield return "Paris";  yield return "London";  } } 

Python 编辑

Python自2001年的2.2版开始支持生成器[6]。下面是生成器一个例子,它是个计数器:

def countfrom(n): while True: yield n n += 1 # 例子使用: 打印出从10到20的整数 # 注意这个迭代通常会终止,尽管  # countfrom()被写为了无限循环 for i in countfrom(10): if i <= 20: print(i) else: break 

另一个生成器例子,它按需要无尽的产生素数:

import itertools def primes(): yield 2 n = 3 p = [] while True: # 这有效于Python 2.5+  if not any(n % f == 0 for f in itertools.takewhile(lambda f: f*f <= n, p)): yield n p.append(n) n += 2 

Python的生成器可以认为是一个迭代器包含了冻结的栈帧。当用next()方法调用迭代器,Python恢复冻结的栈帧,继续执行至下一次的yield语句。生成器的栈帧再一次冻结,被yield的值返回给调用者。

PEP 380 (Python 3.3开始)增加了yield from表达式,允许生成器将它的一部份操作委托给另一个生成器。[10]

生成器表达式 编辑

Python拥有建模于列表推导式的一种语法,叫做生成器表达式,用来辅助生成器的创建。下面的例子扩展了上面第一个例子,使用生成器表达式来计算来自countfrom生成器函数的数的平方:

squares = ( n*n for n in countfrom(2) ) for j in squares: if j <= 20: print(j) else: break 

Smalltalk 编辑

下面例子使用Pharo Smalltalk黄金分割率生成器对goldenRatio next调用,每次返回一个更加逼近的黄金分割率:

goldenRatio := Generator on: [ :g | | x y z r | x := 0. y := 1. [ z := x + y. r := (z / y) asFloat. x := y. y := z. g yield: r ] repeat ]. goldenRatio next. 

下面的表达式返回的下次10逼近

(1 to: 10) collect: [ :dummy | goldenRatio next]. 

参见 编辑

注释 编辑

  1. ^ 存档副本. [2017-11-30]. (原始内容于2020-06-25). 
  2. ^ Kiselyov, Oleg. General ways to traverse collections in Scheme. January 2004 [2017-11-30]. (原始内容于2019-12-22). 
  3. ^ O. -J. Dahl; C. A. R. Hoare. Hierarchical Program Structures. C. A. R. Hoare (编). Structured Programming. London, UK: Academic Press. 1972: 175–220. ISBN 978-0122005503. In SIMULA, a coroutine is represented by an object of some class, co-operating by means of resume instructions with objects of the same or another class, which are named by means of reference variables. ……
    Thus a main program may establish a coroutine relationship with an object that it has generated, using the call/detach mechanism instead of the more symmetric resume/resume mechanism. In this case, the generated object remains subordinate to the main program, and for this reason is sometimes known as a Semicoroutine. ……
    Let X and Y be objects, generated by a "master program" M. Assume that M issues a call (X), thereby invoking an "active phase" of X, terminated by a detach operation in X; and then issues a call (Y), and so forth. In this way M may act as a "supervisor" sequencing a pattern of active phases of X, Y, and other objects. Each object is a "slave", which responds with an active phase each time it is called for, whereas M has the responsibility to define the large scale pattern of the entire computation.
    Alternatively the decision making may be "decentralised", allowing an object itself to determine its dynamic successor by a resume operation. The operation resume (Y), executed by X, combines an exit out of X (by detach) and a subsequent call (Y), thereby bypassing M. Obligation to return to M is transferred to Y.
     
  4. ^ The Icon Programming Language utilizes generators to implement its goal directed evaluation. In Icon, generators can be invoked in contexts outside of the normal looping control structures.
  5. ^ Liskov, Barbara. (PDF). April 1992 [2008-03-08]. (原始内容 (pdf)存档于2003-09-17). 
  6. ^ 6.0 6.1 Python Enhancement Proposals: PEP 255: Simple Generators (页面存档备份,存于互联网档案馆), PEP 289: Generator Expressions (页面存档备份,存于互联网档案馆), PEP 342: Coroutines via Enhanced Generators (页面存档备份,存于互联网档案馆
  7. ^ yield (C# Reference). [2017-11-30]. (原始内容于2016-11-16). 
  8. ^ Liskov, B.; Snyder, A.; Atkinson, R.; Schaffert, C. Abstraction mechanisms in CLU. Communications of the ACM. 1977, 20 (8). doi:10.1145/359763.359789. 
  9. ^ 存档副本. [2017-11-30]. (原始内容于2019-02-07). 
  10. ^ PEP 380 -- Syntax for Delegating to a Subgenerator. [2017-11-30]. (原始内容于2020-06-04). 

参考文献 编辑

  • Stephan Murer, Stephen Omohundro, David Stoutamire and Clemens Szyperski: Iteration abstraction in Sather. ACM Transactions on Programming Languages and Systems, 18(1):1-15 (1996) [1] (页面存档备份,存于互联网档案馆

生成器, 计算机编程, 关于与, 標題相近或相同的条目, 請見, 生成器, 生成器, generator, 是计算机科学中特殊的子程序, 实际上, 所有生成器都是迭代器, 生成器非常类似于返回数组的函数, 都是具有参数, 可被调用, 产生一系列的值, 但是生成器不是构造出数组包含所有的值并一次性返回, 而是每次产生一个值, 因此生成器看起来像函数, 但行为像迭代器, 生成器可以用更有表达力的控制流结构实现, 如协程或头等計算續體, 生成器, 也被称作半协程, semicoroutine, 是特殊的, 能力更弱的协程. 关于与 生成器 计算机编程 標題相近或相同的条目 請見 生成器 生成器 Generator 是计算机科学中特殊的子程序 实际上 所有生成器都是迭代器 1 生成器非常类似于返回数组的函数 都是具有参数 可被调用 产生一系列的值 但是生成器不是构造出数组包含所有的值并一次性返回 而是每次产生一个值 因此生成器看起来像函数 但行为像迭代器 生成器可以用更有表达力的控制流结构实现 如协程或头等計算續體 2 生成器 也被称作半协程 semicoroutine 3 是特殊的 能力更弱的协程 总是在传回一个值时把控制交还给调用者 而不是像协程那样指出另一个协程继续执行 目录 1 使用 2 历史 3 语言实例 3 1 CLU 3 2 Icon 3 3 C 3 4 C 3 5 Python 3 5 1 生成器表达式 3 6 Smalltalk 4 参见 5 注释 6 参考文献使用 编辑生成器通常在一个循环内部被调用 4 生成器第一次被调用是在进入这个循环结构时 创建一个对象以封装生成器的状态 绑定的实参 生成器的实体接着被执行直至遇到一个特别的yield动作 在这里提供给yield动作的值被返回给调用者 在下一次调用同一个生成器的时候 生成器从yield动作之后恢复执行 直到遇上另一个yield动作 生成器的执行也可以遇到finish动作而终止 由于生成器在需要的才计算它的要被yield的值 因此可以用来代表一个串流 这种序列要一次性全部计算出来是昂贵的甚至是不可能的 这种情况还包括无穷序列或现场数据串流 如果需要及早求值 主要是在序列是有限的时候 否则求值将永不终止 可以使用列表或使用并行结构来创建一个列表替代生成器 例如 Python的一个生成器g 通过l list g 可被求值成列表l 而在F 中 序列表达式seq 将除了 之外的惰性的 生成器或序列 求值为及早的 列表 在有生成器出现的情况下 语言的循环构造 比如for和while 可以归约成一个单一的loop end loop构造 可以用合适的生成器以正确的方式 顺畅的模拟所有常见的循环构造 例如 一个按范围的循环如for x 1 to 10 可以通过生成器而被实现为迭代 比如Python的for x in range 1 10 进一步的 break可以被实现为向生成器发送finish 而接着在循环中使用continue 历史 编辑生成器最早出现于CLU语言 1975年 5 也是字符串操纵语言Icon 1977年 的显著特征 它现在出现在Python 6 C 7 Ruby 最新版本的ECMAScript ES6 ES2015 与其他语言之中 在CLU与C 中 生成器称作迭代器 在Ruby称作枚举器 语言实例 编辑CLU 编辑 CLU使用yield语句来在用户定义数据抽象上进行迭代 8 string chars iter s string yields char index int 1 limit int string size s while index lt limit do yield string fetch s index index index 1 end end string chars for c char in string chars s do end Icon 编辑 在Icon中 所有表达式 包括循环 都是生成器 语言有很多内建生成器 甚至使用生成器机制实现某些逻辑语义 逻辑析取或OR以此达成 打印从0到20的平方 可以如下这样使用协程完成 local squares j squares create seq 0 2 every j squares do if j lt 20 then write j else break 但是多数时候 定制生成器是使用suspend关键字来实现 它的功能完全类似CLU中的yield关键字 C 编辑 使用宏预处理的例子见 9 generator descent place for all variables used in the generator int i our counter place the constructor of our generator e g descent int minv int maxv from emit to stop is a body of our generator emit int will emit int values Start of body of the generator for i 10 i gt 0 i yield i a k a yield in Python returns next number in 1 10 reversed stop stop end of sequence End of body of the generator 可迭代 int main int argc char argv descent gen for int n gen n get next generator invocation printf next number is d n n return 0 C 11提供的foreach loop可用于任何具有begin与end成员函数的类 还需要有operator operator 与operator 例如 include lt iostream gt int main for int i range 10 std cout lt lt i lt lt std endl return 0 一个基本实现 class range private int last int iter public range int end last end iter 0 Iterable functions const range amp begin const return this const range amp end const return this Iterator functions bool operator const range amp const return iter lt last void operator iter int operator const return iter C 编辑 C 2 0开始可以利用yield构造生成器 Method that takes an iterable input possibly an array and returns all even numbers public static IEnumerable lt int gt GetEven IEnumerable lt int gt numbers foreach int i in numbers if i 2 0 yield return i 可以使用多个yield return语句 public class CityCollection IEnumerable lt string gt public IEnumerator lt string gt GetEnumerator yield return New York yield return Paris yield return London Python 编辑 Python自2001年的2 2版开始支持生成器 6 下面是生成器一个例子 它是个计数器 def countfrom n while True yield n n 1 例子使用 打印出从10到20的整数 注意这个迭代通常会终止 尽管 countfrom 被写为了无限循环 for i in countfrom 10 if i lt 20 print i else break 另一个生成器例子 它按需要无尽的产生素数 import itertools def primes yield 2 n 3 p while True 这有效于Python 2 5 if not any n f 0 for f in itertools takewhile lambda f f f lt n p yield n p append n n 2 Python的生成器可以认为是一个迭代器包含了冻结的栈帧 当用next 方法调用迭代器 Python恢复冻结的栈帧 继续执行至下一次的yield语句 生成器的栈帧再一次冻结 被yield的值返回给调用者 PEP 380 Python 3 3开始 增加了yield from表达式 允许生成器将它的一部份操作委托给另一个生成器 10 生成器表达式 编辑 Python拥有建模于列表推导式的一种语法 叫做生成器表达式 用来辅助生成器的创建 下面的例子扩展了上面第一个例子 使用生成器表达式来计算来自countfrom生成器函数的数的平方 squares n n for n in countfrom 2 for j in squares if j lt 20 print j else break Smalltalk 编辑 下面例子使用Pharo Smalltalk 黄金分割率生成器对goldenRatio next调用 每次返回一个更加逼近的黄金分割率 goldenRatio Generator on g x y z r x 0 y 1 z x y r z y asFloat x y y z g yield r repeat goldenRatio next 下面的表达式返回的下次10个逼近 1 to 10 collect dummy goldenRatio next 参见 编辑列表推导式 迭代器 Iteratee 英语 Iteratee 惰性求值 Corecursion 英语 Corecursion 协程 計算續體注释 编辑 存档副本 2017 11 30 原始内容存档于2020 06 25 Kiselyov Oleg General ways to traverse collections in Scheme January 2004 2017 11 30 原始内容存档于2019 12 22 O J Dahl C A R Hoare Hierarchical Program Structures C A R Hoare 编 Structured Programming London UK Academic Press 1972 175 220 ISBN 978 0122005503 In SIMULA a coroutine is represented by an object of some class co operating by means of resume instructions with objects of the same or another class which are named by means of reference variables Thus a main program may establish a coroutine relationship with an object that it has generated using the call detach mechanism instead of the more symmetric resume resume mechanism In this case the generated object remains subordinate to the main program and for this reason is sometimes known as a Semicoroutine Let X and Y be objects generated by a master program M Assume that M issues a call X thereby invoking an active phase of X terminated by a detach operation in X and then issues a call Y and so forth In this way M may act as a supervisor sequencing a pattern of active phases of X Y and other objects Each object is a slave which responds with an active phase each time it is called for whereas M has the responsibility to define the large scale pattern of the entire computation Alternatively the decision making may be decentralised allowing an object itself to determine its dynamic successor by a resume operation The operation resume Y executed by X combines an exit out of X by detach and a subsequent call Y thereby bypassing M Obligation to return to M is transferred to Y The Icon Programming Language utilizes generators to implement its goal directed evaluation In Icon generators can be invoked in contexts outside of the normal looping control structures Liskov Barbara A History of CLU PDF April 1992 2008 03 08 原始内容 pdf 存档于2003 09 17 6 0 6 1 Python Enhancement Proposals PEP 255 Simple Generators 页面存档备份 存于互联网档案馆 PEP 289 Generator Expressions 页面存档备份 存于互联网档案馆 PEP 342 Coroutines via Enhanced Generators 页面存档备份 存于互联网档案馆 yield C Reference 2017 11 30 原始内容存档于2016 11 16 Liskov B Snyder A Atkinson R Schaffert C Abstraction mechanisms in CLU Communications of the ACM 1977 20 8 doi 10 1145 359763 359789 存档副本 2017 11 30 原始内容存档于2019 02 07 PEP 380 Syntax for Delegating to a Subgenerator 2017 11 30 原始内容存档于2020 06 04 参考文献 编辑Stephan Murer Stephen Omohundro David Stoutamire and Clemens Szyperski Iteration abstraction in Sather ACM Transactions on Programming Languages and Systems 18 1 1 15 1996 1 页面存档备份 存于互联网档案馆 取自 https zh wikipedia org w index php title 生成器 计算机编程 amp oldid 71250297, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。