0

I am a wring a custom class called queue that uses iterator. I have an Iterator class in a seperate file called iterator.py. I get the error below when I try to iterate using for loop.

 from iterator import Iterator
    class Abstractstruc(object):
        def __init__(self):
            assert False
        def __str__(self):
            return "<%s: %s>" %(self.__class__.__name__,self.container)

class Queue(Abstractstruc,Iterator):

    def __init__(self, objecttype=object):
        self.container=[]
        self.size=0

    def add(self, data):
        self.container.append(data)


    def  remove(self):
        self.container.pop(0)


    def __getitem__(self,index):
        return self.container[index]


    def __iter__(self):
        return Iterator(self.container)

if __name__=='__main__':

    q=Queue(int)
    q.add(5)
    q.add(4)
    q.add(6)

    for i in q:
       print i

iterator.py

class Iterator(object):
    def __init__(self, wrapped):
        self.wrapped = wrapped
        self.offset = 0

    def __next__(self):
        if self.offset>=len(self.wrapped):
            raise StopIteration
        else:
            item = self.wrapped[self.offset]
            self.offset+=1
            return item

I get this error message

<Queue: [5, 4, 6]>
<Queue: [4, 6]>
4
Traceback (most recent call last):
  File "queue.py", line 78, in <module>
    for i in q:
TypeError: iter() returned non-iterator of type 'Iterator'

I do not understand why it is not returning an iterator. what fixes needed here?

brain storm
  • 30,124
  • 69
  • 225
  • 393
  • See http://docs.python.org/3/library/stdtypes.html#iterator-types: *The iterator objects themselves are required to support the following two methods, which together form the iterator protocol*, showing you need to implement `__next__` and `__iter__`. – Martijn Pieters Nov 22 '13 at 22:26
  • @MartijnPieters - Did the spelling of `__next__` change from Python2 to Python3? Never mind, I see that it did. In Python2, one must implement `Iterator.next()`; in Python3 it is `Iterator.__next__()`. – Robᵩ Nov 22 '13 at 22:28
  • @Robᵩ: it did; it was renamed from `.next()` to `.__next__()`. – Martijn Pieters Nov 22 '13 at 22:30

2 Answers2

3

Iterators must themselves implement __iter__. They can just return self. From docs, note that custom iterator objects must support __iter__ to support for and in statements. Also, as @Robᵩ noted, since you are using Python 2 instead of 3, you need to implement next(), not __next__().

Silas Ray
  • 25,682
  • 5
  • 48
  • 63
  • 1
    Also, we can infer from his `print` statement that he is using Python2. So he needs to rename `.__next__()` to `.next()`. – Robᵩ Nov 22 '13 at 22:31
  • @Robᵩ Good catch in the inference of Python version. I added it already, but I'll adjust the addition to account for that. – Silas Ray Nov 22 '13 at 22:32
1

That's because next() method should not be magic, you don't need double underscores. As mentioned before, Python 3 is different.

def next(self):
rocknrollnerd
  • 2,564
  • 1
  • 16
  • 20
  • 1
    Good observation, but there is a subtly here. In Python3 one _does_ need the underscores. Perhaps the OP read some Python3 docs and didn't realize that they were completely applicable. – Robᵩ Nov 22 '13 at 22:34
  • I've changed my comment. Thanks for the tip! I should definitely get closer to Python3. – rocknrollnerd Nov 22 '13 at 22:36