【问题标题】:Why do list and tuple change the output of enumerate?为什么 list 和 tuple 会改变 enumerate 的输出?
【发布时间】:2013-04-24 23:42:10
【问题描述】:

我对以下行为感到惊讶:

>>> a=['a','b','c','d','e','f','g']
>>> en=enumerate(a)
>>> list(en)
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e'), (5, 'f'), (6, 'g')]
>>> list(en)
[]
>>> # en changed?   let's try that again!
>>> a=['a','b','c','d','e','f','g']
>>> en=enumerate(a)
>>> tuple(en)
((0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e'), (5, 'f'), (6, 'g'))
>>> tuple(en)
()
>>> # en changes again?

我假设list() 只会从 en 中的数据构造一个列表,并且不会以任何方式更改它。与tuple() 相同。但它们都以“深刻”的方式影响 en。我是误解了list()tuple(),还是误解了enumerate()?谢谢。

【问题讨论】:

  • 另外,你没有要求它,但也许你希望枚举表现得像一个列表,你总是可以做 en=list(enumerate(a))。这会将可迭代的 enumerate(a) 耗尽到列表中,并将列表分配给 en。
  • 感谢大家的回答!现在清楚多了。

标签: python list tuples enumerate


【解决方案1】:

我认为你误解了 enumerate()。

>>> en=enumerate(a)

是生成器/迭代器,而不是数据结构。一旦你通过'en'运行一次,通过创建列表,生成器已经运行并且什么都没有了。再次尝试 list(en) 是在尝试遍历一个已经到达终点的迭代器,所以那里什么都没有。

【讨论】:

  • enumerate 是一个迭代器,而不是一个生成器/迭代器。 >>> inspect.isgenerator(enumerate([]))False>>> import collections>>> isinstance(enumerate([]), collections.Iterator)True
  • 在 2 中,你是对的。我相信 3 所有内置迭代器都是生成器(例如,不需要 xrange)。
  • 你错了,你从哪里听说过 Python 3? xrange 既不是迭代器也不是生成器。它是一个惰性求值的序列对象(与 Py3k 的 range 相同)。您可能想到的唯一迭代器是在迭代xrange 序列时创建的rangeiterator 对象。迭代器和生成器仍然不同,特别是生成器不是线程安全的
【解决方案2】:

enumerate 返回 iterator,而不是像列表那样的 iterable。这意味着listtuple只能通过重复调用其next()方法直到迭代器耗尽,然后迭代器和Python中的所有其他迭代器一样,才能获得enumerate的返回值的所有元素, 将无法再生成任何元素。

【讨论】:

    【解决方案3】:

    listtuple 也没有什么特别之处。无论您使用en,都会发生这种情况,包括通过您自己手写的for 循环:

    >>> a=['a','b','c','d','e','f','g']
    >>> en=enumerate(a)
    >>> en
    <enumerate object at 0x21172d0>
    >>> for index, elem in en:
    ...   print index, elem
    ... 
    0 a
    1 b
    2 c
    3 d
    4 e
    5 f
    6 g
    >>> for index, elem in en:
    ...   print index, elem
    ... 
    >>> 
    

    请注意,en 是“枚举对象”,而不是列表或元组,打印它并没有尝试打印其内容。这是因为enumerate 实际上并没有生成包含与a 相同的所有数据以及索引值的数据结构。相反,它返回一个小对象,该对象在内部记住它正在迭代的容器、它到达的位置以及它达到的计数。这就是生成“下一个”值所需的全部内容,因此即使它不是容器本身也可以对其进行迭代。

    这样做的原因是人们几乎从不存储enumerate 的结果,通常调用它以立即使用for 循环对其进行迭代。为此,花时间和内存来构建所有数据的副本并一次将所有索引保存在内存中是浪费时间和内存的。随时生产就足够了。

    如果您确实需要存储来自enumerate 的结果数据以多次使用(或在生成它的地方以外的其他地方使用),那么您将需要该副本。实现这一点的最简单方法实际上是执行en = list(enumerate(a)) 之类的操作。然后,您可以完全按照您的预期使用en

    【讨论】:

      【解决方案4】:

      您可能不完全理解enumerate()(或者,我可能误解了这个问题)。查看 help(enumerate) 文档(特别是关于 yielding pairsindexvalue:

      Help on class enumerate in module __builtin__:
      
      class enumerate(object)
       |  enumerate(iterable[, start]) -> iterator for index, value of iterable
       |
       |  Return an enumerate object.  iterable must be another object that supports
       |  iteration.  The enumerate object yields pairs containing a count (from
       |  start, which defaults to zero) and a value yielded by the iterable argument.
       |  enumerate is useful for obtaining an indexed list:
       |      (0, seq[0]), (1, seq[1]), (2, seq[2]), ...
       |
       |  Methods defined here:
       |
       |  __getattribute__(...)
       |      x.__getattribute__('name') <==> x.name
       |
       |  __iter__(...)
       |      x.__iter__() <==> iter(x)
       |
       |  next(...)
       |      x.next() -> the next value, or raise StopIteration
       |
       |  ----------------------------------------------------------------------
       |  Data and other attributes defined here:
       |
       |  __new__ = <built-in method __new__ of type object>
       |      T.__new__(S, ...) -> a new object with type S, a subtype of T
      

      【讨论】:

        猜你喜欢
        • 2013-03-17
        • 1970-01-01
        • 2022-11-30
        • 1970-01-01
        • 1970-01-01
        • 2019-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多