oo_dispenser
oo_dispenser

Reputation: 7

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

Upvotes: 0

Views: 414

Answers (2)

wwii
wwii

Reputation: 23763

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

  • Printing relevant data/comparisons/... can be a useful tool.
  • Stepping through the code with pencil and paper can also be useful - Be The Interpreter
  • If you are using an IDE, learning its debugging features should be high on a list of priorities.

Upvotes: 2

Kuldip Chaudhari
Kuldip Chaudhari

Reputation: 1112

Try this

class Prime:
    def __init__(self, n):
        self.n = n
        self.current = 2
    def __iter__(self):
        for i in range(self.current, self.n+1):
            pflag = True
            for j in range(2, i):
                if i%j == 0:
                    pflag=False
                    break
                    
            if pflag:
                self.current=i
                yield i
d = Prime(20)
c = iter(d)
print(next(c))
print(next(c))
print(next(c))
print(next(c))
print(next(c))
print(next(c))
print(next(c))

Upvotes: 0

Related Questions