[Python-ideas] Introduce collections.Reiterable

Steven D'Aprano steve at pearwood.info
Fri Sep 20 14:45:05 CEST 2013


On Fri, Sep 20, 2013 at 06:18:47AM -0400, Neil Girdhar wrote:
> On Fri, Sep 20, 2013 at 5:48 AM, Steven D'Aprano <steve at pearwood.info>wrote:
> 
> > On Thu, Sep 19, 2013 at 11:02:57PM +1000, Nick Coghlan wrote:
> > > On 19 September 2013 22:18, Steven D'Aprano <steve at pearwood.info> wrote:
> > [...]
> > > > At the moment, dict views aren't directly iterable (you can't call
> > > > next() on them). But in principle they could have been designed as
> > > > re-iterable iterators.
> > >
> > > That's not what iterable means. The iterable/iterator distinction is
> > > well defined and reflected in the collections ABCs:
> >
> > Actually, I think the collections ABC gets it wrong, according to both
> > common practice and the definition given in the glossary:
> >
> > http://docs.python.org/3.4/glossary.html
> 
> 
> Where does the glossary disagree with collections.abc?

I show below a class that is iterable, yet is not an instance of 
collections.Iterable. By the glossary definition it is iterable (it has 
a __getitem__ method that raises IndexError when there are no more items 
to be returned).


[...]
> What you're calling "indirectly iterable" is what the docs call "Iterable"
> and what collections.abc call Iterable, right?

I've explained this further in my reply to Paul Moore. What I should 
have said was *manually* iterable, in the sense of directly calling 
__next__ or __getitem__ on the view.


Here's an example of an iterable class that collections.Iterable claims 
is not an iterable:

> > py> class Seq:
> > ...     def __getitem__(self, index):
> > ...             if 0 <= index < 5: return index+1000
> > ...             raise IndexError
> > ...
> > py> s = Seq()
> > py> isinstance(s, Iterable)
> > False
> > py> list(s)  # definitely iterable
> > [1000, 1001, 1002, 1003, 1004]
> >
> 
> PEP 3119 makes it clear that isinstance( collections.Sequence) is the de
> facto way of checking whether something is a sequence.

I'm not testing whether it is a sequence. I explicitly stated it isn't a 
sequence, since it doesn't implement __len__. The Sequence ABC gets this 
right.


> Casting to list is not the de facto way.

No, but casting to list demonstrates that it can be iterated over. In my 
reply to Paul, I explicitly used it in a for-loop.


> Therefore, Seq is neither Iterable nor a Sequence
> according to collections.abc.

I'm not concerned by Sequence. It's not a Sequence. No dispute there. 
But it is an iterable, since it obeys the sequence protocol and can be 
iterated over. (Which is not the same as being a sequence.)


> > (Note that although Seq obeys the sequence protocol, and is can be
> > iterated over, it is not a fully-fledged Sequence since it has no
> > __len__.)
> >
> 
> I guess we disagree that Seq obeys the sequence protocol.

I'm not sure why you think it doesn't obey the sequence protocol. It is 
demonstrably true that it does. If it wasn't obvious from the source 
code, it should be obvious from a few seconds' experimentation at the 
interactive interpreter:

py> s = Seq()
py> s[0]
1000
py> s[1]
1001
[...cut s[2], s[3], s[4] for brevity...]
py> s[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __getitem__
IndexError


That's all there is to the sequence protocol, and it's enough to make 
Seq objects iterable.


-- 
Steven


More information about the Python-ideas mailing list