Как проверить, действительно ли итератор является контейнером итератора?
у меня есть фиктивный пример контейнера итератора ниже (реальный читает файл, слишком большой, чтобы поместиться в памяти):
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))
Как проверить функцию normalise, что мне передается контейнер итератора, а не обычный генератор?
2 ответов
прежде всего: нет такой вещи, как итератор контейнера. У вас есть типа Iterable.
iterable создает итератор. Любой итератор-это тоже итерируемые, но производит как итератор:
>>> list_iter = iter([])
>>> iter(list_iter) is list_iter
True
у вас нет итератора, если iter(ob) is ob
тест false.
вы можете проверить есть ли у вас итератор (отсчитывается с момента next
поднимает StopIteration
исключение) vs просто iterable (возможно, может повторяться несколько раз) с помощью collections.abc
модуль. Вот пример:
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()
an Iterator
является наличие как __next__
и __iter__
магические методы (и кстати, в основном то, что происходит за кулисами, когда вы называете isinstance
на collections.abc
аннотация базовый класс-это тест на наличие определенных магических методов).
обратите внимание, что итератор тоже Iterable
, как и пустой список (т. е. оба имеют __iter__
магический метод):
isinstance(i, Iterable) # True
isinstance(a, Iterable) # True
также обратите внимание,как было указано в ответ Мартин Питерс', что при применении generic iter()
функция для обоих, вы получаете итератор:
isinstance(iter(my_iterator()), Iterator) # True
isinstance(iter([])), Iterator) # True
разница здесь между []
и my_iterator()
это iter(my_iterator())
возвращает как итератор, тогда как iter([])
производит новый итератор каждый раз.
как уже упоминалось в том же ответе MP, ваш объект выше не является "контейнером итератора"."Это итерируемый объект, т. е. "повторяемое". Независимо от того," содержит " ли он что-то, на самом деле не связано; понятие содержания представлено абстрактным базовым классом Container
. А Container
может быть iterable, но это не обязательно должно быть.