为什么要将发生器传入iter以使用其生成器功能?

时间:2017-09-02 20:29:18

标签: python python-2.7 generator sequence

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

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函数调用到生成器?代码仍然运行并在没有它的情况下打印正确的值。

2 个答案:

答案 0 :(得分:2)

take不知道它是接收迭代器(例如生成器)还是容器(例如list / tuple / set)。在后一种情况下,容器没有与它们关联的.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来电。

答案 1 :(得分:0)

如果您将listtuple传递给take函数,则他们不会使用next方法。

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

iter上使用list将为您提供listiterator,其中包含next方法。

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