简体   繁体   English

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

[英]How do I check if an iterator is actually an iterator container?

I have a dummy example of an iterator container below (the real one reads a file too large to fit in memory): 我有一个下面的迭代器容器的虚拟示例(真正的读取文件太大而不适合内存):

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

This allows me to iterate over the value more than once so that I can implement something like this: 这允许我多次迭代该值以便我可以实现这样的事情:

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

How do I check in the normalise function that I am being passed an iterator container rather than a normal generator? 如何检查normalize函数,我正在传递一个迭代器容器而不是一个普通的生成器?

First of all: There is no such thing as a iterator container . 首先:没有迭代器容器这样的东西。 You have an iterable . 你有一个可迭代的

An iterable produces an iterator. 迭代生成迭代器。 Any iterator is also an iterable, but produces itself as the iterator: 任何迭代器也是可迭代的,但它自己生成迭代器:

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

You don't have an iterator if the iter(ob) is ob test is false. 如果iter(ob) is ob test,则没有迭代器。

You can test whether you have an iterator (is consumed once next raises the StopIteration exception) vs just an iterable (can probably be iterated over multiple times) by using the collections.abc module . 您可以使用collections.abc模块测试是否有迭代器( next一次使用StopIteration异常消耗)与只有迭代(可能多次迭代)。 Here is an example: 这是一个例子:

from collections.abc import Iterable, Iterator

def my_iterator(): 
    yield 1

i = my_iterator()
a = []

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

What makes my_iterator() an Iterator is the presence of both the __next__ and __iter__ magic methods (and by the way, basically what is happening behind the scenes when you call isinstance on a collections.abc abstract base class is a test for the presence of certain magic methods). 是什么让my_iterator()Iterator是既存在__next____iter__魔术方法(顺便说一句,基本上发生了什么事,当你调用幕后isinstancecollections.abc抽象基类是存在的测试某些神奇的方法)。

Note that an iterator is also an Iterable , as is the empty list (ie, both have the __iter__ magic method): 注意迭代器也是一个Iterable ,就像空列表一样(即两者都有__iter__魔术方法):

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

Also note, as was pointed out in Martijn Pieters' answer , that when you apply the generic iter() function to both, you get an iterator: 还要注意, 正如Martijn Pieters的回答所指出的 ,当你将泛型iter()函数应用于两者时,你会得到一个迭代器:

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

The difference here between [] and my_iterator() is that iter(my_iterator()) returns itself as the iterator, whereas iter([]) produces a new iterator every time. []my_iterator()之间的区别在于iter(my_iterator()) 将自身作为迭代器返回 ,而iter([])每次都会生成一个新的迭代器

As was already mentioned in MP's same answer, your object above is not an "iterator container." 正如在MP的相同答案中已经提到的,上面的对象不是“迭代器容器”。 It is an iterable object, ie, "an iterable". 它是一个可迭代的对象,即“可迭代的”。 Whether or not it "contains" something isn't really related; 它是否“包含”某些东西并不是真正相关的; the concept of containing is represented by the abstract base class Container . contains的概念由抽象基类Container A Container may be iterable, but it doesn't necessarily have to be. Container可以是可迭代的,但它不一定必须是可迭代的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM