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

How do I check if an iterator is actually an iterator container?

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

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))

我如何检查正在传递给迭代器容器而不是普通生成器的规范化函数?

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

一个可迭代对象产生一个迭代器。任何迭代器也是可迭代的,但会生成 自身 作为迭代器:

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

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

你可以测试你是否有一个迭代器(消耗一次 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__ 魔术方法的存在(顺便说一句,基本上是幕后发生的事情当您在 collections.abc 抽象基础上调用 isinstance 时,class 是对某些魔术方法是否存在的测试)。

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

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

另请注意,,当您将通用 iter() 函数应用于两者时,您会得到一个迭代器:

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

这里[]my_iterator()的区别是iter(my_iterator())returns本身作为迭代器,而iter([]) 每次都会产生一个 新的迭代器

正如 MP 的相同回答中已经提到的,您上面的对象不是 "iterator container." 它是一个可迭代对象,即 "an iterable"。它是否 "contains" 没有真正相关的东西;包含的概念由抽象基 class Container 表示。 Container 可能是可迭代的,但不一定是。