Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I subclass collections.Iterator?

According to the documentation on ABCs, I should just have to add a next method to be able to subclass collections.Iterator. So, I'm using the following class:

class DummyClass(collections.Iterator):
    def next(self):
        return 1

However, I get an error when I try to instantiate it:

>>> x = DummyClass()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class DummyClass with abstract methods __next__

I'm guessing that I'm doing something stupid, but I can't figure out what it is. Can anyone shed some light on this? I could add a __next__ method, but I was under the impression that was only for C classes.

like image 363
Jason Baker Avatar asked Dec 22 '22 23:12

Jason Baker


2 Answers

Looks like you are using Python 3.x. Your code works fine on Python 2.x.

>>> import collections
>>> class DummyClass(collections.Iterator):
...     def next(self):
...         return 1
... 
>>> x = DummyClass()
>>> zip(x, [1,2,3,4])
[(1, 1), (1, 2), (1, 3), (1, 4)]

But on Python 3.x, you should implement __next__ instead of next, as shown in the table of the py3k doc. (Remember to read the correct version!)

>>> import collections
>>> class DummyClass(collections.Iterator):
...     def next(self):
...         return 1
... 
>>> x = DummyClass()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can’t instantiate abstract class DummyClass with abstract methods __next__
>>> class DummyClass3k(collections.Iterator):
...     def __next__(self):
...         return 2
... 
>>> y = DummyClass3k()
>>> list(zip(y, [1,2,3,4]))
[(2, 1), (2, 2), (2, 3), (2, 4)]

This change is introduced by PEP-3114 — Renaming iterator.next() to iterator.__next__().

like image 73
kennytm Avatar answered Dec 26 '22 11:12

kennytm


It's not necessary to inherit from the Iterator class to make the object iterable. But in my case that was required, so did it like this:

from collections.abc import Iterator

class MyIterator(Iterator):

    def __init__(self, items, property1, property2):
        self.items = items
        self.property1 = property1
        self.property2 = property2
    
    def __iter__(self):
        return self.items.__iter__()

    def __next__(self):
        return self.items.__next__()

The test code is:

my_iterator = MyIterator([1, 2, 3], "value 1", 2)

for item in my_iterator:
    print(f'{item} ', end='')
print()
print(my_iterator.property1)
print(my_iterator.property2)

And the output is:

1 2 3
value 1
2

The documentation is: class collections.abc.Iterator

like image 23
Alex Avatar answered Dec 26 '22 10:12

Alex