生成器是一种特殊的迭代器,它有一些普通迭代器没有的方法,如 send(), close() ..等等 可以通过使用如下的genexp获得生成器:
g=(i for i in range(3))
g的类型将是一个生成器。 但是对我来说, g 是一个生成器似乎很奇怪,因为 g.send 什么也不会做,因为g不是由 yield 的函数返回的关键字,并且没有机会捕获send方法传递的值(不确定这是对的),我没有看到 g 需要成为生成器而不是生成器的原因更通用的类型:迭代器。
答案 0 :(得分:1)
似乎对定义存在一些误解:
__iter__
的对象。此外,__iter__
还应返回迭代器。next
。yield
关键字的函数。有些作者使用上述其中一个含义中的通用生成器名称。你必须知道上下文才能真正理解他们所指的是什么。但由于所有这些对象都紧密相关,因此它并没有真正的问题。
总是很难回答问题"为什么会这样?"在询问命名约定时。除非你问原创作者几乎不可能提供满意的答案。例如,它可能只是进化的影响,因为我们都知道进化确实会引入错误。但这是我的猜测:
生成器表达式和生成器函数都生成相同类型的对象。现在为什么他们生产相同的物体?这可能是因为它是最简单的方式来实现它,就像在幕后。这可能是动机。
另请注意,迭代器和生成器表达式之间存在显着差异:您可以在生成器表达式中使用yield
关键字。尽管它并没有真正有用并且引入了许多混淆,但这种行为根本不是直观的。
资源:
答案 1 :(得分:0)
lambda函数以某种方式受到限制(没有控制结构,没有文档字符串),但会创建一个真正的函数对象。您可能会以同样的方式问,为什么lambda函数的__doc__
属性返回None
而不是AttributeError
,因为没有lambda函数可能有文档字符串?
对于基本类型的值,某种值的子类型应为substitutable。 (特殊情况并不足以打破规则。)
>>> def g(): yield
>>> type(g())
<class 'generator'>
>>> h = (i for i in [1,2,3])
>>> type(h)
<class 'generator'>
生成器表达式在语法上看起来像列表解析,但生成的值具有类型生成器迭代器,因此应该可以使用与使用yield
生成的值相同的方式使用发电机功能。在这种情况下,调用.send(foo)
除了推进函数体之外什么都不做。
答案 2 :(得分:0)
虽然genexps不需要且无法从send
功能中受益,但它们是在send
之前引入的。那时,生成器没有通用迭代器的额外API功能。
即使send
首先出现,也可能会使语言更复杂,以便为genxps记录和实现另一个迭代器类型来评估,而不是重用发生器设计。