How to 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 a 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 to check the normalize function that they pass me an iterator container, and not a regular generator?

+6
source share
2 answers

First of all: there is no such thing as an iterator container. You have iterability.

An iterator creates an iterator. Any iterator is also iterable, but produces itself as an iterator:

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

You don't have an iterator if the iter(ob) is ob test iter(ob) is ob incorrect.

+8
source

You can check if you have an iterator (consumed once next raises a StopIteration exception) against just repeating (maybe repeating several times) using collections.abc module . 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 does my_iterator() a Iterator have the __next__ and __iter__ magic methods (and by the way, basically what happens behind the scenes when you call isinstance on collections.abc abstract base class is a test for the presence of certain magic methods).

Note that the iterator is also Iterable , like an empty list (i.e. both have a magic __iter__ method):

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

Also note, as Martijn Pieters answer pointed out , that when you use the generic iter() function for both, you get an iterator:

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

The difference between [] and my_iterator() is that iter(my_iterator()) returns itself as an iterator, while iter([]) creates a new iterator each time.

As MP mentioned in a similar answer, your object above is not an “iterator container”. This is an iterable object, i.e. Iterable. Whether it is “containing” something is not really connected; the concept of addition is represented by the abstract base class Container . A Container can be iterable, but this is optional.

+2
source

All Articles