【问题标题】:Why does genexp(generator expression) is called genexp? not iterexp?为什么 genexp(generator expression) 叫 genexp?不是迭代?
【发布时间】:2017-10-12 02:50:30
【问题描述】:

生成器是一种特殊的迭代器,它有一些普通迭代器没有的方法,如send()close().. 。 等等。 可以使用如下的 genexp 获得生成器:

g=(i for i in range(3))

g 的类型将是一个生成器。 但对我来说,g 是一个生成器似乎很奇怪,因为 g.send 什么都不做,因为具有 yield 的函数不会返回 g关键字,并且没有机会捕获 send 方法传递的值(不确定这是正确的),我看不出 g 需要成为生成器而不是生成器的原因更泛化类型:迭代器。

【问题讨论】:

  • 您能否链接到声明声明的来源?
  • 声称什么?内容都是我自己说的,如有错误请指正tks!
  • 我的意思是,请喜欢参考资料。 :-)
  • @Tobias - 我也不知道你想要什么。
  • 链接到语言规范,上面写着:“这些东西被称为某某。”

标签: python python-internals


【解决方案1】:

似乎对定义有些误解:

  1. Iterable 是一个实现__iter__ 的对象。 __iter__ 也应该返回一个迭代器。
  2. Iterator 是一个实现next 的对象。
  3. 生成器函数是一个带有yield关键字的函数。
  4. 生成器对象 是生成器函数返回的对象。每个生成器对象也是一个迭代器。
  5. 生成器表达式 是列表推导的生成器版本。生成器表达式的结果也称为 generator object 或简称为 generator

一些作者在上述含义之一中使用通用的 generator 名称。您必须了解上下文才能真正理解它们所指的内容。但由于所有这些对象都紧密相连,因此没有真正的问题。

总是很难回答“为什么会这样?”的问题。在询问命名约定时。除非您询问原始创作者,否则几乎不可能提供令人满意的答案。例如,它可能只是进化的结果,众所周知,进化确实会引入错误。但这是我的猜测:

生成器表达式和生成器函数都生成相同类型的对象。现在为什么它们会产生相同的对象?这可能是因为它是在引擎盖下实现它的最简单方法。这可能是动机。

另请注意,迭代器和生成器表达式之间存在显着差异:您可以在生成器表达式中使用 yield 关键字。尽管它并不是真正有用并且会引起很多混乱,但这种行为根本不直观。

资源:

https://wiki.python.org/moin/Iterator

https://wiki.python.org/moin/Generators

【讨论】:

  • 是的,我理解这两者之间的区别,我的问题是,如果 genexp 返回的对象不能与 send 方法做任何事情,那么有这个方法是什么意思?
  • @LtChang 正如您所指出的,不可能将代码放在接受外部数据的生成器表达式中(即使您实际上可以在生成器表达式中使用yield)。所以这个函数什么都不做。没有任何意义。但这不是一个真正的问题。就像你有一个带有简单定义方法的类的子类。
  • 再次:问题“为什么要这样设计?”超出了我的能力范围。我想你得问问作者。
  • 如果有人有时间,可能值得研究一下引入这些功能的 PEP,以便进行动机和设计选择。
【解决方案2】:

lambda 函数在某些方面受到限制(没有控制结构,没有文档字符串),但会创建一个真正的函数对象。你可能会问同样的问题,为什么 lambda 函数有一个返回 None__doc__ 属性,而不是 AttributeError,因为没有 lambda 函数可能有 doc 字符串?

对于基类型的值,某种值的子类型应该是substitutable。 (而且特殊情况还不足以打破规则。)

>>> def g(): yield
>>> type(g())
<class 'generator'>
>>> h = (i for i in [1,2,3])
>>> type(h)
<class 'generator'>

生成器表达式在语法上看起来像一个列表推导式,但生成的值具有 generator iterator 类型,因此应该可以与在生成器函数中使用 yield 生成的值相同.在这种情况下,调用 .send(foo) 除了推进函数体之外什么都不做。

【讨论】:

  • 我认为这并不能真正回答问题。由 genexp 产生的东西有一个send,因为它是一个生成器,但问题似乎是在问,如果它对send 没有任何用处,为什么这个值根本就是一个生成器。这个答案没有说明为什么 genexps 被设计为创建生成器。
【解决方案3】:

虽然 genexp 不需要也无法从 send 功能中受益,但它们是在 send 出现之前引入的。那时,生成器没有泛型迭代器之外的其他 API 功能。

即使 send 最先出现,它也可能会使语言更加复杂,以记录和实现另一种迭代器类型以供 genexps 评估,而不是重用生成器设计。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    • 2011-02-05
    相关资源
    最近更新 更多