2

I have just learned about iterators in Python however I am having a hard time implementing them.

I am trying to write a class to so that this loop works:

  odds = OddNumbers(13)
  for i in odds:
      print(i) 

I want to write an iter() function and next() function to do this.

So far I have:

class OddNumbers:

    def __init__(self, number):
        self.number = number

    def __iter__(self):
        return self

    def __next__(self):
        current = self.number
        if self.number%2 == 0:
            return current
        else:
            raise StopIteration

But at the moment this is returning nothing. I expect the output to be

1
3
5
7
9
11
13

Help?

7
  • What are you trying to do? You have only one element. Why do you need this class to be an iterable? Commented May 14, 2015 at 5:55
  • 1
    What numbers should the example code print? Commented May 14, 2015 at 5:56
  • If you start with an odd number, then __next__ will only raise StopIteration. If you start with an even number, it will only return that number. Did you mean for __next__ to decrement self.number each time? Commented May 14, 2015 at 5:58
  • @user2357112 Apologies for not putting that in my original post, I forgot! I have edited it in now though.
    – ASm
    Commented May 14, 2015 at 5:58
  • In your case, __next__ will raise an exception in the first loop, so the iterator stopped, that's why there is nothing print.
    – WKPlus
    Commented May 14, 2015 at 5:59

4 Answers 4

3

Your object needs to keep track of its state and update it when __next__ is called.

class OddNumbers(object):
    def __init__(self, number):
        self.current = ...
        self.number = number

    def __iter__(self):
        return self

    def __next__(self):
        # Update self.current
        # If the limit has been reached, raise StopIteration
        # Otherwise, return something
1

You need another variable to track the current number:

def __init__(self, number):
    self.number = number
    self.current = 1

Then you need to compare it with the ending number, and maybe increment it:

def __next__(self):
    if self.current > self.number:
        raise StopIteration
    current = self.current
    self.current += 2
    return current
4
  • Thank you very much! This solved my issue! At one stage I did have another variable to track the number of iterations, except I didn't initialize it with the init method, I only introduced it in the next. Thank you again!
    – ASm
    Commented May 14, 2015 at 6:07
  • You shouldn't tell the OP the whole answer, this doesn't teach them anything.
    – augurar
    Commented May 14, 2015 at 6:18
  • 1
    @augurar, the OP showed effort and posted real code so an answer is the right response. The comment showed he learned from this. Commented May 14, 2015 at 6:26
  • @BrentWashburne You just told him the answer. So he learned what the correct answer was. Good job, I guess.
    – augurar
    Commented May 14, 2015 at 6:26
0

There is probably a much cleaner way of doing this, but here is a quick stab:

class OddNumbers:

    def __init__(self, number):
        self.number = number

    def __iter__(self):
        self.current = self.number
        return self

    def __next__(self):
        if self.current > 0:
            if self.current % 2 == 0:
                self.current -= 1
            self.current -= 1
            return self.current + 1
        raise StopIteration
0

This will give you an iterator-like object which provides even or odd numbers. However, it won't satisfy your for loop semantics as it is not a true iterator.

class NumberIterator(object):
    """Returns simple even/odd number iterators."""
    def __init__(self, current):
        self.current = current
    def next(self):
        self.current += 2
        return self.current
    @classmethod
    def getOddIterator(cls):
        return cls(-1) # start at 1
    @classmethod
    def getEvenIterator(cls):
        return cls(0) # start at 2


    odd_numbers = NumberIterator.getOddIterator()
    even_numbers = NumberIterator.getEvenIterator()

    odd_numbers.next() # Returns 1
    odd_numbers.next() # Returns 3

Not the answer you're looking for? Browse other questions tagged or ask your own question.