【问题标题】:What does it mean to "consume" in Python? In an iterator?在 Python 中“消费”是什么意思?在迭代器中?
【发布时间】:2011-07-08 10:20:39
【问题描述】:

我已经使用 Python 工作了几个月了,我突然想到,我经常忽略那些乍看之下无法理解的词汇,而是试图了解一个想法的要点。现在回想起来,我仍然对consume这个词的含义感到困惑。我最初的兴趣来自对迭代器的解释,它谈到了正在消耗的迭代器的值。但是,环顾四周,这在 Python 词典中似乎并不常见。或者是吗?在这里挖掘发现主要是对 Web 服务的引用,以及关于如何隐藏函数的这个或那个结果的一两个讨论。

我想,把我的无知分解成几个基点:

  1. “消费”在不同的 Python 语境中会做不同的事情吗?
  2. 数据在被消费时会发生什么情况,例如iter() 中的数据?
  3. 当一个变量被分配给迭代器的结果(据称是消耗的数据)时,它是否不再属于迭代器?
  4. 能否在一次调用迭代器时从迭代器对象中使用多个值?

我希望这有点道理。请注意,这不是针对任何特定需求;我只是感到困惑,超出了合理的合理性。

编辑:还有一件事...迭代值(使用next() 调用时)是否保留在内存中?

【问题讨论】:

  • 我的意思是,使用了 consume 这个词。一个链接会很好(我发现的唯一参考是在itertools 文档中)。
  • doughellmann.com/PyMOTW/itertools --- "由于由 tee() 创建的新迭代器共享输入,你不应该再使用原来的迭代器。如果你确实使用来自原始输入的值,新的迭代器不会产生这些值:"
  • C# WPF 文章中也有很多“消耗”。

标签: python iterator


【解决方案1】:

术语“consume”是一个非正式术语,指的是迭代器在 Python 中的工作方式。 “迭代器”是负责创建某些元素序列的单个对象。这个序列可能是现有列表的元素,也可能是经过计算的东西,如素数或 π 的小数位。

当调用者向迭代器请求“下一个”项时,迭代器会提供下一项,然后更改自己的状态,以便在此之后生成下一项。这通常是您所期望的。

如果我有一个生成素数递增序列的生成器,我第一次调用它时会得到 2 作为回报。下一次,我会得到 3。如果我给你一个对那个生成器的引用,你会调用它(你认为是第一次)并得到 5。没有任何方法可以“重置”生成器,因此它将再次从 2 开始,除非创建一个全新的生成器实例。在那种情况下,我可以说在给你发电机之前我已经消耗前两项了。

【讨论】:

  • 那么,在迭代器对象的情况下,使用一个值就像.pop()ing 一样?如果你愿意,从牌组中取出一张牌?
  • 是的,这是一种思考方式。但是,请注意,列表上的迭代器不会修改列表本身。迭代器是一个独立的对象,它按顺序生成列表的元素。
  • 这是一个困难的概念,我还没有完全理解它的所有细节。但是您成功地给出了清晰而扎实的解释。 +1
【解决方案2】:

关于 2.

事实上,我们必须区分两种情况。

记住 Greg Hewgill 写的:

“迭代器”是负责的单个对象 用于创建一些元素序列。 这个序列可能是现有列表的元素, 或者它可能是计算出来的,比如素数 或π的小数位。

第一种情况

迭代器计算受刺激时它必须产生的对象;也就是说,在调用 next() 之前,生成的对象是不存在的。因此,如果为对象分配了名称,则后者将继续存在;如果不是,则该对象会在一定时间内不与命名空间中的名称绑定而存在,然后它将在内存中消失,也就是说它所占用的位将在以后或早日用于另一个对象。

第二种情况

是当迭代器返回以前存在的属于列表、元组、字典等的对象时。在这种情况下,next() 生成的每个对象都已经具有名称绑定。然后,如果对象在“弹出”迭代器时被分配了一个新名称,那么将有两个名称绑定到该对象。并且如果对象没有被分配一个名字,它将继续只绑定一个名字,这足以维持对象的存活。

共同点:

每次调用迭代器生成对象时,如果没有为其分配名称,则操作的唯一结果是迭代器已被“消费”。这是一种说法,即使在生成对象后没有永久性后果,它也发生了一些在迭代器内部留下痕迹的事情。

也有人说在为对象分配名称时使用迭代器,但是,我不想混淆。

注意:

事实上,如果一个对象预先存在于一个列表中,比如说,它可能没有名字。但是列表包含了它“包含”的每个对象的引用……事实上,列表并不“包含”对象,而只是对对象的引用……嗯,这超出了我想说的范围。

.

关于3

你不应该写3:“当一个变量被赋值给...”

变量这个词在 Python 中是一个陷阱,因为它的含义不明确。 Python 中没有变量,在其他语言中众所周知的常识中,即 « 值可以改变的内存的分隔部分»。只有对象. 变量这个词习惯性地用来表示一个标识符。因此,最好将其称为 identifiername。这样可以避免混淆。

.

关于4

我不认为只需要一次调用next()就可以从迭代器中获得两次返回

【讨论】:

  • 很棒的解释,也很完整。太棒了。 :)
  • “Python 中没有变量”:这真的没用。 “在其他语言中的常识中”,您的意思是“在 C 中”。许多语言都像 Python 一样工作,并且在所有语言中调用变量都非常有意义。
  • @Ned Batchelder 虽然,理解 Python 的数据模型是基于对象而不是变量对我很有帮助。我不是唯一一个明白这一点的人。 - 如果其他语言像 Python 一样工作,则不能证明 Python 有变量。相反,这意味着这些其他语言没有变量。顺便问一下,这些其他语言是什么?
  • 其他语言有 PHP、Ruby、Lisp、Perl 等,它们都有变量。这些变量是可以引用值的名称。变量是一个名称,其值可以随时间变化。 C 的做法与 Python 不同。这并不意味着 Python 没有变量。
【解决方案3】:

我不是 Python 专家,但我可以这样说:大多数时候,编程中的消耗与生产相反。您可以将一些流程归类为生产者,它们创造价值;和其他人作为消费者,他们使用生产者创造的价值。

在迭代器的情况下,迭代器是一个生产者,它遍历一个可迭代对象并按顺序“生产”每个值,一次一个。 “消费”来自迭代器的数据只是意味着使用它。

【讨论】:

  • 还有:生产者的另一个词是“发电机”;在 Python 中,这恰好是指一种特定类型的操作。 :-)
  • Greg Hewgill 的回答比我的回答更有用、更丰富。我只是在非常高的水平上回答这个问题。
【解决方案4】:

Iterators 只是支持__iter__next 方法的对象。迭代器的一般用例是循环遍历它们,每次循环时,iterator.next() 的结果将被分配给一个变量。

考虑到这一点,对iterator.next() 的调用可以称为“使用值”,因为通常对next 的调用会更改迭代器的状态,并且无法返回到之前的状态状态。

但是,没有什么可以阻止迭代器重复返回相同的值,或者甚至提供回滚到先前状态的方法。在这些情况下,使用“消费”一词可能并不适用。

至于迭代器的next方法返回的数据会发生什么,完全依赖于迭代器的实现。生成器倾向于丢弃它们产生的结果,但如果容器也是迭代器,那么调用next() 时返回的数据仍将存在于容器对象中。

【讨论】:

    【解决方案5】:

    我可以回答您的第一点,消费就是耗尽一个可迭代对象,这意味着将可迭代对象从下一个项目中耗尽。

    【讨论】:

      【解决方案6】:

      “消费”在不同的 Python 语境中会做不同的事情吗?

      不,“消费”总是做同样的事情。

      数据在被消费时会发生什么,比如在iter()中?

      它在您获得它的地方不再可用。

      当一个变量被分配给一个迭代器的结果——据称被消耗的数据——它不再属于迭代器了吗?

      正确。一旦迭代器产生数据,数据就不再属于迭代器。

      您能否在一次调用迭代器时从一个迭代器对象中使用多个值?

      通常,不会。但是,您可以编写一个自定义迭代器,一次生成多个值。

      【讨论】:

        猜你喜欢
        • 2017-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-20
        • 2010-10-23
        • 1970-01-01
        • 2023-03-06
        • 2013-07-11
        相关资源
        最近更新 更多