如何检查迭代器是否实际上是迭代器容器?

时间:2015-07-06 12:00:32

标签: python python-3.x generator

下面有一个迭代器容器的虚拟示例(真实的读取文件太大而无法放入内存中):

class DummyIterator:
    def __init__(self, max_value):
        self.max_value = max_value

    def __iter__(self):
        for i in range(self.max_value):
            yield i

def regular_dummy_iterator(max_value):
    for i in range(max_value):
        yield i

这允许我多次迭代,以便我可以实现以下内容:

def normalise(data):
    total = sum(i for i in data)
    for val in data:
        yield val / total

# this works when I call next()
normalise(DummyIterator(100))

# this doesn't work when I call next()
normalise(regular_dummy_iterator(100))

如何检查normalize函数我是否正在传递迭代器容器而不是普通生成器?

2 个答案:

答案 0 :(得分:9)

首先:没有迭代器容器这样的东西。你有一个 iterable

iterable生成迭代器。任何迭代器也是可迭代的,但产生本身作为迭代器:

>>> list_iter = iter([])
>>> iter(list_iter) is list_iter
True

如果iter(ob) is ob测试为false,则没有迭代器。

答案 1 :(得分:3)

你可以测试你是否有一个迭代器(在next引发StopIteration异常时消耗)vs 只是一个迭代(可能多次迭代)使用collections.abcmodule。这是一个例子:

from collections.abc import Iterable, Iterator

def my_iterator(): 
    yield 1

i = my_iterator()
a = []

isinstance(i, Iterator) # True
isinstance(a, Iterator) # False

使my_iterator()成为Iterator的原因是__next____iter__魔术方法的存在(顺便说一句,基本上是当你在幕后发生的事情)在isinstance抽象基类上调用collections.abc是对某些魔术方法的存在的测试。

请注意,迭代器也是Iterable ,空列表也是如此(即,两者都具有__iter__魔法方法):

isinstance(i, Iterable) # True
isinstance(a, Iterable) # True

另请注意,as was pointed out in Martijn Pieters' answer,当您将通用iter()函数应用于两者时,您将得到一个迭代器:

isinstance(iter(my_iterator()), Iterator) # True
isinstance(iter([])), Iterator) # True

[]my_iterator()之间的区别在于iter(my_iterator()) 将自己作为迭代器返回,而iter([])会产生 new迭代器每一次。

正如在MP的相同答案中已经提到的,上面的对象不是"迭代器容器。"它是一个可迭代的对象,即"可迭代的"。是否"包含"事情并不是真正相关的; contains的概念由抽象基类Container表示。 Container可以是可迭代的,但并非必须如此。