How do I call a method from another method? - python

I am coding a program in python. I introduce an entire number and the program gives back to me the decomposition in prime factors of this number.
For example 6 ---> 3, 2. Another example 16 --> 2, 2, 2, 2.
I am doing it with OOP. I have created a class (PrimeFactors) with 2 methods (is_prime and prime_factor_decomposition). The first method says wether the number is prime, and the second gives the decomposition back.
This is the code:
class PrimeFactors(object):
def __init__(self, number):
self.number = number
def is_prime(self):
n = self.number - 1
a = 0
loop = True
if self.number == 1 or self.number == 2:
loop = False
while n >= 2 and loop:
if self.number % n != 0:
n -= 1
else:
a += 1
loop = False
return a == 0
def prime_factor_decomposition(self):
factors = []
n = self.number - 1
loop = True
if PrimeFactors.is_prime(self.number):
factors.append(self.number)
loop = False
while n >= 2 and loop:
if self.number % n == 0 and PrimeFactors.is_prime(n):
factors.append(n)
self.number = self.number / n
if self.number % n == 0:
n += 1
n -= 1
return factors
s = PrimeFactors(37)
print(s.is_prime())
I am getting a mistake. I think it is something related to the method call.
My question is, How can I call a method from another method if they both are from the same class?

You need to use self. to call another method of the same class:
class Foo:
def __init__(self):
pass
def method1(self):
print('Method 1')
def method2(self):
print('Method 2')
self.method1()

Jkdc's answer is absolutely correct. I also wanted to note that your method calls are going to be problematic. You defined is_prime to take self as its only argument, but when you call it, you're passing in self.number or n.
If you need is_prime to work with arbitrary numbers, and not just whatever the class was initialized with, you should add an extra argument.

Just a general advise: there are good (and FAST!) algorithms to check if a number is prime. your loop starts with n-1, thats highly inefficient. lets say the number is
1000000, so your algorithm starts with 999999, but the first even POSSIBLE number is the half of n! so instead i would go from 2 up to n/2:
for i in range(n/2):
if self.number%i==0:
return true
return false
i think even better for your purpose is to return not a boolean, but the number, which is found to be the divisor:
for i in range(n/2):
if self.number%i==0:
return i
return 0
then you can repeatedly call the method and will only get the prime numbers.

Related

How can I ensure that a function is "defined" in Python?

Trying to learn python as a java programmer. I would really appreciate some insight into why my program is telling me that my "isPrime" function isn't defined, especially with the use of 'self.'
import math
class Problem10:
def sumOfPrimesX(self, number):
sum = 0
for i in range(0, number):
if isPrime(i):
sum += i
return sum
def isPrime(self, x):
for n in range(0, math.floor(x/2)):
if x % n == 0:
return False
return True
print(sumOfPrimesX(input()))
all functions need it as their first parameter in a python program
No, only the instance methods, the methods related to a specific instance of a class. A simple function can need to parameter.
And you won't see the parameter self filled with the classic way of calling it, if you call the method on a instance it'll be filled by it
p = Problem10()
p.sumOfPrimesX(int(input("Give a value"))) # call on instance, one paramater given
# same as
Problem10.sumOfPrimesX(Problem10(), int(input("Give a value")))
# call on class itself, need to pass an instance as first to fill 'self
Also you need to wrap the input in an int, also start the loop at 2
p = Problem10()
print(p.sumOfPrimesX(int(input("Give a value"))))
class Problem10:
def isPrime(self, x):
for n in range(2, math.floor(x / 2)):
if x % n == 0:
return False
return True
The issue is both isPrime and sumofPrimesX are methods of the class Problem10.
Try the following:
import math
class Problem10:
def sumOfPrimesX(self, number):
sum = 0
for i in range(0, number):
if self.isPrime(i):
sum += i
return sum
def isPrime(self, x):
for n in range(0, math.floor(x/2)):
if x % n == 0:
return False
return True
pv = Problem10()
print(pv.sumOfPrimesX(input()))

What is the problem in this code? i get an Error in this code [duplicate]

I am coding a program in python. I introduce an entire number and the program gives back to me the decomposition in prime factors of this number.
For example 6 ---> 3, 2. Another example 16 --> 2, 2, 2, 2.
I am doing it with OOP. I have created a class (PrimeFactors) with 2 methods (is_prime and prime_factor_decomposition). The first method says wether the number is prime, and the second gives the decomposition back.
This is the code:
class PrimeFactors(object):
def __init__(self, number):
self.number = number
def is_prime(self):
n = self.number - 1
a = 0
loop = True
if self.number == 1 or self.number == 2:
loop = False
while n >= 2 and loop:
if self.number % n != 0:
n -= 1
else:
a += 1
loop = False
return a == 0
def prime_factor_decomposition(self):
factors = []
n = self.number - 1
loop = True
if PrimeFactors.is_prime(self.number):
factors.append(self.number)
loop = False
while n >= 2 and loop:
if self.number % n == 0 and PrimeFactors.is_prime(n):
factors.append(n)
self.number = self.number / n
if self.number % n == 0:
n += 1
n -= 1
return factors
s = PrimeFactors(37)
print(s.is_prime())
I am getting a mistake. I think it is something related to the method call.
My question is, How can I call a method from another method if they both are from the same class?
You need to use self. to call another method of the same class:
class Foo:
def __init__(self):
pass
def method1(self):
print('Method 1')
def method2(self):
print('Method 2')
self.method1()
Jkdc's answer is absolutely correct. I also wanted to note that your method calls are going to be problematic. You defined is_prime to take self as its only argument, but when you call it, you're passing in self.number or n.
If you need is_prime to work with arbitrary numbers, and not just whatever the class was initialized with, you should add an extra argument.
Just a general advise: there are good (and FAST!) algorithms to check if a number is prime. your loop starts with n-1, thats highly inefficient. lets say the number is
1000000, so your algorithm starts with 999999, but the first even POSSIBLE number is the half of n! so instead i would go from 2 up to n/2:
for i in range(n/2):
if self.number%i==0:
return true
return false
i think even better for your purpose is to return not a boolean, but the number, which is found to be the divisor:
for i in range(n/2):
if self.number%i==0:
return i
return 0
then you can repeatedly call the method and will only get the prime numbers.

Replacing global vars

Below, I came up with artificially passing the reference var n2 from f2() to g2(x) instead of the global var n in f() and the nested g(). Any other better ways to replace global vars in this case?
from random import randint
# global value var
def f():
global n
n=0
def g():
global n
if randint(1,100)>50: n+=1
for _ in range(100): g()
print(n)
# local reference var
def f2():
n2=[0]
for _ in range(100): g2(n2)
print(n2[0])
def g2(x):
if randint(1,100)>50: x[0]+=1
Short answer: You are trying to pass by reference an immutable value (integer) and want to update it. Wrapping that in a tiny class, or list, or dict like you're doing is the way to go. But there are other ways if you are able to slightly modify your code.
Longer answer: (Note: This might not be a direct answer to your question.)
I understand this is an artificial example. But think about your real problem --Does g2() need to know that there is a variable that is supposed to update as a part of its invocation? Is there a way that the responsibility of updating a variable belongs to that which defines it? How about f2() is the one that defines the variables and also updates it? That way you can limit all the changes to that variable to a very small perimeter (f2()).
My approach in that case would be something like:
def f2():
n2 = 0
for _ in range(100):
n2 += g2()
print(n2)
def g2():
return 1 if randint(1,100)>50 else 0
From working with functional languages, and from trying to write reproducible tests, I've generally tried to adopt a rule that a function should declare all of its inputs as parameters, and produce all of its outputs as return values: to the maximum extent possible a function should never have side effects. Using the global keyword probably indicates you're breaking this rule.
For example, your "g" function takes the current state variable and either increments it or doesn't. You don't need a global for that (and you don't need it to be a nested function either):
from random import randint
def g(n):
"""Returns either n or n+1, with 50% probability."""
if randint(1,100)>50:
return n+1
else:
return n
Then the iterating function can call that a bunch of times:
def f():
"""Produces a number between 0 and 100 with $DISTRIBUTION."""
n = 0
for _ in range(100):
n = g(n)
return n
And finally at the top level:
if __name__ == '__main__':
print(f())
Since we're never totally sure about our code, we can write some tests.
def test_f():
n = f()
assert n >= 0 and n < 100
def test_g():
n = g(0)
assert n == 0 or n == 1
def test_g_dist():
count = 100
ns = [g(0) for _ in range(count)]
assert(all(n == 0 or n == 1) for n in ns)
zeros = len([n for n in ns if n == 0])
ones = len([n for n in ns if n == 1])
assert zeros + ones == count
# won't always pass; probability of failure left as an exercise
assert zeros > 0.45 * count and zeros < 0.55 * count
Notice that I can call f() and g(n) as many times as I want and they'll never interfere with anything else. Running my own unit tests at startup time would be a little unusual, but I'm free to if that's what I want to do.

Printing None instead of nothing when interacting linked list

I have a linked list where I iterate within a range and return all of the square numbers that can be represented as integers within this range. Instead of just returning just the numbers that this can be done to it will return None in between for example 9, None, None...,16, None, None..., 25 I wanting it to just return 9, 16, 25 etc etc
class Squares:
def __init__(self, start, end):
self.__start = start - 1
self.__end = end -1
def __iter__(self):
return SquareIterator(self.__start, self.__end)
class SquareIterator:
def __init__(self, start, end):
self.__current = start
self.__step = 1
self.__end = end
def __next__(self):
if self.__current > self.__end:
raise StopIteration
else:
self.__current += self.__step
x = self.__current - self.__step + 1
self.__current - self.__step + 1
if str(x).isdigit() and math.sqrt(x) % 1 == 0:
return x
You need to make your __next__ function continue to loop until it gets to the target value:
def __next__(self):
# We're just going to keep looping. Loop breaking logic is below.
while True:
# out of bounds
if self.__current > self.__end:
raise StopIteration
# We need to get the current value
x = self.__current
# increase the state *after* grabbing it for test
self.__current += self.__step
# Test the value stored above
if math.sqrt(x) % 1 == 0:
return x
The reason you should be storing x, then incrementing is that you have to increment no matter what, even if you don't have a perfect square.
It is unclear why you are complicating things; there is a simple way:
import math
class Squares:
def __init__(self, start, end):
self.__start = start
self.__end = end
self.__step = 1
def __iter__(self):
for x in range(self.__start, self.__end, self.__step):
if math.sqrt(x) % 1 == 0:
yield x
s = Squares(0, 100)
for sq in s:
print(sq, end=' ')
output:
0 1 4 9 16 25 36 49 64 81
from the comments:
Mind you, it would likely be much easier to avoid the dedicated
iterator class, and just implement __iter__ for Squares as a generator
function. Explicit __next__ involves all sorts of inefficient state
management that Python does poorly, and isn't all that easy to follow;
__iter__ as a generator function is usually very straightforward; every time you hit a yield it's like the return from __next__, but all
your state is function local, no special objects involved (generators
take care of saving and restoring said local state). – ShadowRanger>
it probably doesn't even need a Squares class. A generator function
named squares would do what's needed; pass it start, stop and step and
use them as local variables, rather than attributes of some
unnecessary self. Only real advantage to the class is that it could be
iterated repeatedly without reconstructing it, a likely uncommon use
case
def squares_from(start, stop, step=1):
"""returns a generator function for the perfect squares
in the range comprised between start and stop, iterated over using step=step
"""
for x in range(start, stop, step):
if math.sqrt(x) % 1 == 0:
yield x
for sq in squares_from(0, 100):
print(sq, end=' ')

Calculate nth term of Fibonacci sequence in Python

The following code is to calculate nth term og fibonacci sequence in python using matrix exponentiation for various test cases t.But the program gives absurd output.Please tell me where i am wrong.when i ran the code in C++ it runs perfectly.
class matrix:
def __init__(self):
self.a=self.b=self.c=1
self.d=0
def mul(self,e,f):
ret = matrix()
ret.a=(e.a*f.a)+(e.b+f.c)
ret.b=(e.a*f.b)+(e.b+f.d)
ret.c=(e.c*f.a)+(e.d+f.c)
ret.d=(e.c*f.b)+(e.d+f.d)
return ret
def exp(self,a,p):
if(p==0):
temp=matrix()
temp.a=temp.b=temp.c=temp.d=1
return temp
if(p==1):
return a
if(p%2==0):
return self.exp(self.mul(a,a),p/2)
else:
return self.mul(a,self.exp(self.mul(a,a),(p-1)/2))
def fib(self,n):
if (n==0):
return 0
if (n==1):
return 1
s=matrix()
s=self.exp(s,n)
return s.d
t=int(raw_input())
while(t>0):
v=matrix()
n=int(raw_input())
print v.fib(n)
t=t-1
The problem lies in your __init__ function. In python the so-called variables are just 'tags' to data in the memory. To compare with C/C++, these can be thought of as pointers. when you assign self.a = self.b = self.c, you are basically assigning three different names to the same data in the memory. Any change you make in a will be reflected back in b and c and so on.
For your problem where you need three separate variables, one way to change the __init__ function is like:
self.a, self.b, self.c = 1, 1, 1
or you can use copy. copy() tells python to assign a new memory location and then assign the tag on the right hand side to that location. For more read the official documentation on this http://docs.python.org/2/library/copy.html. You can also read a short walk-through on this in Python Tutorial: Shallow and Deep-copy
There are several issues, in order of importance:
1) Your multiplication is wrong. Note the multiplications at the right where you have sums):
def mul(self,e,f):
ret = matrix()
ret.a=(e.a*f.a)+(e.b*f.c)
ret.b=(e.a*f.b)+(e.b*f.d)
ret.c=(e.c*f.a)+(e.d*f.c)
ret.d=(e.c*f.b)+(e.d*f.d)
return ret
2) In the last line, you do return s.d but you should return s.b or s.c or you will get one less fibonacci.
3) The line temp.a=temp.b=temp.c=temp.d=1 is not necessary because the constructor does the work. Besides it is wrong, because d should be 0.
4) Why are mul and exp class functions if they don't use self. It does no harm but they should be #staticmethod
5) Again, it does no harm but your second recursive call is unnecessarily complex. Just write:
return matrix.mul(a,matrix.exp(a, p-1))
I'm not sure if it is required for you to use matrix exponentiation for this problem. Unfortunately, I do not know much about Python classes quite yet. However, the following code does what the question heading wants: to find the n-th Fibonacci number. Below I describe this as F_n. Note the initial conditions for low values of n.
def fibN( n ):
"""
fibonacci: int -> int
Returns F_n.
Note: F_1 = 0, F_2 = 1, F_3 = 1, F_4 = 2
"""
n = abs( int( n ))
if n == 0:
fib = 0
elif n == 1:
fib = 1
else:
counter = 2
f0 = 0
f1 = 1
fib = f0 + f1
while counter <= n:
fib = f0 + f1
f0 = f1
f1 = fib
counter += 1
return fib

Categories