下面有一个迭代器容器的虚拟示例(真实的读取文件太大而无法放入内存中):
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函数我是否正在传递迭代器容器而不是普通生成器?
答案 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.abc
module。这是一个例子:
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
可以是可迭代的,但并非必须如此。