【问题标题】:Why pass a generator into iter to use its generator function?为什么将生成器传递给 iter 以使用其生成器功能?
【发布时间】:2018-02-11 13:28:13
【问题描述】:

如果我们考虑以下生成器和生成器函数:

def integers():
    """Infinite sequence of integers."""
    i = 1
    while True:
        yield i
        i = i + 1

def take(n, seq):
    """Returns first n values from the given sequence."""
    seq = iter(seq)
    result = []
    try:
        for i in range(n):
            result.append(seq.next())
    except StopIteration:
        pass
    return result

print take(5, integers()) # prints [1,2,3,4,5]

为什么必须在生成器函数中调用生成器内置的 iter 函数?没有它,代码仍然运行并打印正确的值。

【问题讨论】:

  • 尝试删除该行并传递一个列表。 take([1, 2, 3], 2)

标签: python python-2.7 generator sequence


【解决方案1】:

take 不知道自己接收的是迭代器(如生成器)还是容器(如列表/元组/集合)。在后一种情况下,容器没有与之关联的.next 方法,因此您的代码将失败。你的代码是安全的,而不是冒险,我认为这是良好的编程习惯。


一个例子(在python3中):

def foo():
     yield from [1, 2, 3]

x = iter([1, 2, 3])
y = iter(foo())

print( next(x), next(y) ) # this would be `x.next()` in python2
(1, 1)

在后一种情况下,iter 是多余的,但代码在这两种情况下都有效。但是,请考虑:

x = [1, 2, 3]
print(next(x))
TypeError                                 Traceback (most recent call last)
<ipython-input-351-cf05c93171ef> in <module>()
----> 1 print(next(x))

TypeError: 'list' object is not an iterator

应该清楚为什么需要调用iter

【讨论】:

  • 迭代器可迭代的。这是iterator spec 所要求的。
  • @user2357112 我正在努力寻找正确的措辞......这里什么是合适的?
  • @cᴏʟᴅsᴘᴇᴇᴅ 您可以将它们称为容器。
  • @MosesKoledoye 谢谢!
  • 我通常使用“一些其他可迭代”或“非迭代器可迭代”之类的措辞来适应特别奇怪的可迭代对象,但“容器”涵盖了大多数非迭代可迭代对象,并避免暗示迭代器不是迭代。
【解决方案2】:

如果您将listtuple 传递给您的take 函数,它们将没有next 方法。

>>> [1, 2, 3].next() # AttributeError: 'list' object has no attribute 'next'

list 上使用iter 会得到一个listiterator,它确实有一个next 方法。

>>> my_gen = iter([1, 2, 3])
>>> print(my_gen)
<listiterator object at 0x108390a10>
>>> my_gen.next()
1
>>> next(my_gen)
2

【讨论】:

  • listiterator 是迭代器,但不是生成器
猜你喜欢
  • 2019-08-02
  • 2020-05-16
  • 2014-06-26
  • 2017-05-07
  • 1970-01-01
  • 2016-12-02
  • 2014-08-14
  • 1970-01-01
  • 2014-09-13
相关资源
最近更新 更多