pythonpython-3.xiteratoriterator-protocol

Generate Prime Numbers With Iterator Protocol


I am trying to get a series of prime numbers from 1 to n. Instead of using a range and for loop, i am trying to implement it using the iterator protocol. So far i have the below, but as you will see, it isn't doing what i expect.

class Prime:
    def __init__(self, n):
        self.n = n
        self.current = 1
    def __iter__(self):
        return self
    def __next__(self):
        x = self.current
        self.current += 1
        for num in range(self.current, self.n):
            if num > 1:
                for i in range(2, num):
                    if num % i == 0:
                        break
                else:
                    return num


d = Prime(20)
c = iter(d)
print(next(c))
print(next(c))
print(next(c))
print(next(c))
print(next(c))
print(next(c))

it prints 2,3,5,5,7,7 And the goal is for it to print 2,3,5,7,11...19

I just don't want an answer, if you could please explain how too, i would appreciate it. Thanks


Solution

  • When you call next on the instance you increment current so you can start where you left off. Then you proceed to find the next prime but don't update current. You can kind of see what is happening if you print current with each next call.

    print(f'current:{c.current} | next prime: {next(c)}')
    print(f'current:{c.current} | next prime: {next(c)}')    
    print(f'current:{c.current} | next prime: {next(c)}')
    print(f'current:{c.current} | next prime: {next(c)}')
    print(f'current:{c.current} | next prime: {next(c)}')    # current:5 | next prime: 7
    print(f'current:{c.current} | next prime: {next(c)}')    # current:6 | next prime: 7
    print(f'current:{c.current} | next prime: {next(c)}')    # current:7 | next prime: 11
    print(f'current:{c.current} | next prime: {next(c)}')    # current:8 | next prime: 11
    print(f'current:{c.current} | next prime: {next(c)}')
    
    ...
    

    For example if current is five then the next prime is seven. current is incremented to six then it finds the next prime which is also seven.

    Remove the statement that increments current. Then add a statement to update current when the next prime is found.

    ...
        def __next__(self):
            x = self.current
    ##        self.current += 1
            for num in range(self.current, self.n):
                if num > 1:
                    for i in range(2, num):
                        if num % i == 0:
                            break
                    else:
                        self.current = num + 1 
                        return num