Python: Iterator returns None - python

Here is my code:
class Prizes(object):
def __init__(self, purchases, n, d):
self.p = purchases
self.n = n
self.d = d
self.x = 1
def __iter__(self):
return self
def __next__(self):
print(self.x)
if self.x % self.n == 0 and self.p[self.x - 1] % self.d == 0:
self.x = self.x + 1
return self.x - 1
elif self.x > len(self.p):
raise StopIteration
self.x = self.x + 1
def superPrize(purchases, n, d):
return list(Prizes(purchases, n, d))
An example of usage:
superPrize([12, 43, 13, 465, 1, 13], 2, 3)
The output should be:
[4]
But actual output is:
[None, None, None, 4, None, None].
Why does it happen?

Your problem is your implementation of __next__. When Python calls __next__, it will always expect a return value. However, in your case, it looks like you may not always have a return value each call. Thus, Python uses the default return value of a function - None:
You need some way to keep program control inside of __next__ until you have an actually return value. This can be done using a while-loop:
def __next__(self):
while True:
if self.x % self.n == 0 and self.p[self.x - 1] % self.d == 0:
self.x = self.x + 1
return self.x - 1
elif self.x > len(self.p):
raise StopIteration
self.x = self.x + 1

Wrap it with while so that your method doesn't return a value until you found one:
def __next__(self):
while True:
if self.x % self.n == 0 and self.p[self.x - 1] % self.d == 0:
self.x = self.x + 1
return self.x - 1
elif self.x > len(self.p):
raise StopIteration
self.x = self.x + 1
Things working with iterators call __next__ expecting it to return a value, but the method returns a value only under a condition, otherwise it reaches the end of the method and it returns None.

Related

Trying to Add two Points on ECC but the third point is always not on the curve

I'm using this code to add two points together using finite Fields
class FieldElement():
def __init__(self,num,prime):
if num>=prime or num < 0:
error = "num s not in field"
raise ValueError(error)
self.num = num
self.prime=prime
def __eq__(self,other):
if other is None:
return
return self.num == other.num and self.prime == other.prime
def __ne__(self,other):
return not (self == other)
def __add__ (self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in diffirent fields")
num = (self.num+other.num)%self.prime
return self.__class__(num,self.prime)
def __mul__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (self.num * other.num)%self.prime
return self.__class__(num,self.prime)
def __pow__(self,exponent):
n = exponent%(self.prime-1)
num = pow(self.num,n,self.prime)
return self.__class__(num,self.prime)
def __sub__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (other.num - self.num)%self.prime
return self.__class__(num,self.prime)
def __truediv__(self,other):
if self.prime != other.prime:
raise TypeError("cannot divide two numbers in different Fields")
num = self.num * pow(other.num,self.prime-2,self.prime)%self.prime
return self.__class__(num,self.prime)
class Point ():
def __init__(self, x,y,a,b):
self.a = a
self.b = b
self.y = y
self.x = x
if self.x is None and self.y is None:
return
if (self.y**2) != (self.x**3 + a*x + b):
raise ValueError("{} , {} not in the Curve".format(x.num,y.num))
def __repr__(self):
return "Point({},{}){}_{}".format(self.x,self.y,self.a,self.b)
def __eq__(self,other):
return self.x == other.x and self.y == other.y and self.a == other.a and self.b == other.b
def __add__(self,other):
if other.a != self.a or other.b != self.b:
raise TypeError("Points{},{} are the same curve".format(self,other))
if self.x is None:
return other
if other.x is None:
return self
if other.x == self.x and other.y != self.y:
return self.__class__(None,None,self.a,self.b)
if self != other:
s = (other.y-self.y)/(other.x-self.x)
x = (s**2 - self.x - other.x)
y = s*(self.x - x) - self.y
return self.__class__(x,y,self.a,self.b)
if self == other :
s = (3*self.x**2+self.a)/(2* self.y)
x = s**2-2*self.x
y = s*(self.x-x)-self.y
return self.__class__(x,y,self.a,self.b)
if self == other and self.y == 0*self.x:
return self.__class__(None,None,self.a,self.b)
def __eq__(self,other):
return self.x == other.x and self.y == other.y and self.a==other.a and self.b==other.b
def __mul__(self,other):
numX = self.x * other.x
numY = self.y * other.y
return self.__class__(numX,numY,self.a,self.b)
and the bellow code to test it ,
from test import FieldElement,Point
prime = 223
a = FieldElement(num=0,prime=prime)
b = FieldElement(num=7,prime=prime)
x1 = FieldElement(num=47,prime=prime)
y1 = FieldElement(num=71,prime=prime)
x2 = FieldElement(num=17,prime=prime)
y2 = FieldElement(num=56,prime=prime)
p1 = Point(x1,y1,a,b)
p2 = Point(x2,y2,a,b)
p3 = p1+p2
print(p3)
Whatever points I add I get the same error that the third point is not on the the curve, I think the problem is on if (self.y**2) != (self.x**3 + a*x + b) some how it's not checking the new point correctly or Point __add__ method does not calculate the new point correctly, what am missing here ?
You should test every module before use
In the Field, the subtraction is wrong! you calculate b-a not a-b
def __sub__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (other.num - self.num)%self.prime
return self.__class__(num,self.prime)
must be
def __sub__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (self.num - other.num)%self.prime
return self.__class__(num,self.prime)
The other problem as stated in the other answer doesn't make a problem since the first operand is the member of the class, however, you should use
if (self.y**2) != (self.x**3 + self.a*self.x + self.b):
You should also implement __str__ for your field and point classes to print easy to test your code!
def __str__(self):
return num
I've tested and now works. The below is the SageMath Code (test here) that you can compare the result and use a test base for your code.
E = EllipticCurve(GF(223),[0,7])
print(E)
R1 = E(47,71)
R2 = E(17,56)
print(R1+R2)
I think that the line:
if (self.y**2) != (self.x**3 + a*x + b):
should be
if (self.y**2) != (self.x**3 + self.a*self.x + self.b):
as a, x and b will not be treated as field elements.

How to remove output 'None' when iterator is called?

Well, I wrote an iterator Divisors(n) that gets a natural number n as its argument and generates divisors of n (from the smallest to the largest). Here's code:
class Divisors:
def __init__(self, n):
self.n = n
self.i = 0
def __iter__(self):
return self
def __next__(self):
self.i += 1
if self.i == self.n + 1:
raise StopIteration
if self.n % self.i == 0:
return self.i
But, when I run it, I get:
>>> print([x for x in Divisors(12)])
[1, 2, 3, 4, None, 6, None, None, None, None, None, 12]
Question is: How to remove these None's from list to obtain:
[1, 2, 3, 4, 6, 12]
Yes, I know this can be done like this:
def divisors(n):
i = 1
while i <= n:
if n % i == 0:
yield i
i += 1
but I am interested in way I mentioned above.
You could keep incrementing self.i till it evenly divides the self.n:
class Divisors:
def __init__(self, n):
self.n = n
self.i = 0
def __iter__(self):
return self
def __next__(self):
self.i += 1
if self.i == self.n + 1:
raise StopIteration
# Keep incrementing
while self.n % self.i != 0:
self.i += 1
# Now it is guaranteed to divide
return self.i
I suspect this might work:
def __next__(self):
self.i += 1
if self.i == self.n + 1:
raise StopIteration
if self.n % self.i == 0:
return self.i
else
return self.__next__()
Some perfer the following style which should have a similar effect.
def __next__(self):
self.i += 1
if self.i == self.n + 1:
raise StopIteration
if self.n % self.i == 0:
return self.i
return self.__next__()

Stop __next__ from returning None [duplicate]

Why is my iterator returning extra 'None' in the output. For the parameters/example below, I am getting [None,4,None] instead of the desired [4] Can anyone explain why I am getting the extra None and how I can fix it? The print out 'returning' only appears once so I am assuming only one item should be appended to the returning calling function.
code:
class Prizes(object):
def __init__(self,purchase,n,d):
self.purchase = purchase
self.length = len(purchase)
self.i = n-1
self.n = n
self.d = d
def __iter__(self):
return self
def __next__(self):
if self.i < self.length:
old = self.i
self.i += self.n
if (self.purchase[old])%(self.d) == 0:
print("returning")
return old+1
else:
raise StopIteration
def superPrize(purchases, n, d):
return list(Prizes(purchases, n, d))
purchases = [12, 43, 13, 465, 1, 13]
n = 2
d = 3
print(superPrize(purchases, n, d))
Output:
returning
[None, 4, None]
As people in the comments have pointed out, your line if (self.purchase[old])%(self.d) == 0: leads to the function returning without any return value. If there is no return value supplied None is implied. You need some way of continuing through your list to the next available value that passes this test before returning or raising StopIteration. One easy way of doing this is simply to add an extra else clause to call self.__next__() again if the test fails.
def __next__(self):
if self.i < self.length:
old = self.i
self.i += self.n
if (self.purchase[old])%(self.d) == 0:
print("returning")
return old+1
else:
return self.__next__()
else:
raise StopIteration
Functions return None if you don't have an explicit return statement. That's what happens in __next__ when if (self.purchase[old])%(self.d) == 0: isn't true. You want to stay in your __next__ until it has a value to return.
class Prizes(object):
def __init__(self,purchase,n,d):
self.purchase = purchase
self.length = len(purchase)
self.i = n-1
self.n = n
self.d = d
def __iter__(self):
return self
def __next__(self):
while self.i < self.length:
old = self.i
self.i += self.n
if (self.purchase[old])%(self.d) == 0:
return old+1
raise StopIteration
def superPrize(purchases, n, d):
return list(Prizes(purchases, n, d))
purchases = [12, 43, 13, 465, 1, 13]
n = 2
d = 3
print(superPrize(purchases, n, d))

Python iterator returning unwanted 'None'

Why is my iterator returning extra 'None' in the output. For the parameters/example below, I am getting [None,4,None] instead of the desired [4] Can anyone explain why I am getting the extra None and how I can fix it? The print out 'returning' only appears once so I am assuming only one item should be appended to the returning calling function.
code:
class Prizes(object):
def __init__(self,purchase,n,d):
self.purchase = purchase
self.length = len(purchase)
self.i = n-1
self.n = n
self.d = d
def __iter__(self):
return self
def __next__(self):
if self.i < self.length:
old = self.i
self.i += self.n
if (self.purchase[old])%(self.d) == 0:
print("returning")
return old+1
else:
raise StopIteration
def superPrize(purchases, n, d):
return list(Prizes(purchases, n, d))
purchases = [12, 43, 13, 465, 1, 13]
n = 2
d = 3
print(superPrize(purchases, n, d))
Output:
returning
[None, 4, None]
As people in the comments have pointed out, your line if (self.purchase[old])%(self.d) == 0: leads to the function returning without any return value. If there is no return value supplied None is implied. You need some way of continuing through your list to the next available value that passes this test before returning or raising StopIteration. One easy way of doing this is simply to add an extra else clause to call self.__next__() again if the test fails.
def __next__(self):
if self.i < self.length:
old = self.i
self.i += self.n
if (self.purchase[old])%(self.d) == 0:
print("returning")
return old+1
else:
return self.__next__()
else:
raise StopIteration
Functions return None if you don't have an explicit return statement. That's what happens in __next__ when if (self.purchase[old])%(self.d) == 0: isn't true. You want to stay in your __next__ until it has a value to return.
class Prizes(object):
def __init__(self,purchase,n,d):
self.purchase = purchase
self.length = len(purchase)
self.i = n-1
self.n = n
self.d = d
def __iter__(self):
return self
def __next__(self):
while self.i < self.length:
old = self.i
self.i += self.n
if (self.purchase[old])%(self.d) == 0:
return old+1
raise StopIteration
def superPrize(purchases, n, d):
return list(Prizes(purchases, n, d))
purchases = [12, 43, 13, 465, 1, 13]
n = 2
d = 3
print(superPrize(purchases, n, d))

Recursive division within a class

I'm trying to practice OOP and recursion but I'm having some trouble. I think the recursive aspects of it are correct but the way I'm structuring class is wrong.
How it should work:
It should subtract 1 from 6, until x = 0. Each time adding 1 to index. When x is equal to 0 the function should return index.
Where I'm Getting Errors:
The following code says I have an error because divide accepts three arguements while I've only supplied two. But I thought that self wasn't really an argument. It was just something that had to be done in a class.
How do I make the below code work as intended?
class Division(object):
def __init__(self, x, y):
self.index = 0
self.x = x
self.y = y
def divide(self, x, y):
self.index += 1
if self.x <= 0:
return self.index
return divide(self.x-self.y, self.y)
print(Division.divide(6,1))
Edit (Revised Code):
Now I'm getting an error that divide is not defined?
class Division(object):
def __init__(self):
self.index = 0
def divide(self, x, y):
self.index += 1
if x <= 0:
return self.index
return divide(x-y, y)
print(Division().divide(6,1))
Second Edit:
I think I figured it out. I had to add create an instance of Division again on the divide methods recursive return. My output is wrong though. It's saying self.index is equal to one. Probably because when I create a new instance of the class the index is set to 0. How do I overcome this problem?
Final Code:
class Division(object):
def __init__(self):
self.index = 0
def divide(self, x, y):
self.index += 1
if x <= y:
return self.index
return self.divide(x-y, y)
print(Division().divide(6,1))
I don't understand why you want to have an object here... What does it models ? So here is a solution without object
def divide(a, b, q = 0):
if a < b:
return q
return divide(a-b, b, q+1)

Categories