Modifying an instance of a class when it is created - python-3.x

I have this code:
class Fraction:
def __init__(self, top, bottom):
self.num = top
self.den = bottom
self = self.to_lowest_form()
def to_lowest_form(self):
from math import gcd
d = 0
while d != 1:
d = gcd(self.num, self.den)
self.num //= d
self.den //= d
return Fraction(self.num, self.den)
def __add__(self, other):
pass
As above code shows, I need to get a fraction then put it to its lowest form after it is initialized.
(I get a RecursionError and I know why).
So my question is how can i convert a newly created fraction to its lowest term (so as to avoid calling instance.lowest_form() in every method) ?

You're just making things more complicated by returning a new instance of Fraction when reducing the numerator/denominator in the to_lowest_form method, instead of returning the reduced numbers themselves. Consider keeping the reduced numbers as attributes instead, after calculating their reduced form internally.
Implementation example:
from math import gcd
class Fraction:
def __init__(self, top, bottom):
self.num, self.den = self.reduce(num=top, den=bottom)
#staticmethod
def reduce(num, den):
d = 0
while d != 1:
d = gcd(num, den)
num //= d
den //= d
return num, den

Related

Decorator to get even numbers from Fibonacci

I got a task on courses: Create Fibonacci generator function and create a decorator to leave only even numbers in this sequence. I tried but had no success. Lower I add a code which I try to create.
def decorator(func):
def inner(*args, **kwargs):
print("start decorator")
value = func(*args, **kwargs)
if a%2==0:
print(a)
return value
print("finish decorator")
return inner
#decorator
def fib(n):
a, b = 0, 1
for __ in range(n):
# if a%2==0:
yield a
a, b = b, a + b
print(list(fib(10)))
Please, help to find a way to solve it.

How to pass method name as an argument while calling another method?

I am writing a class wherein I want to use a metric to calculate the score. I should be able to pass the metric as an argument based on which I want to calculate a score. Here is the code I have written. Is there a better approach to solving this situation?
class A:
def __init__(self, region):
self.region = region
def metric1(self, a, b):
returns a*b
def metric2(self, a, b, c):
return self.metric1(a, b) + c
def evaluate(self, metric, a, b, c = None):
if metric = 'metric1':
score = self.metric1(a,b)
elif metric = 'metric2':
score = self.metric2(a,b,c)
return score[0]
obj1 = A('XYZ')
obj1.evaluate('metric2', a, b, c)
Furthermore, I want to write another method that would use the output of the evaluate method to do some other calculations. Is this the right approach to writing a class when we have this chain of outputs from previous methods used in subsequent methods? Or, can we leverage decorators here somehow?
You can access method inside a class by className.methodName (A.metric1) or object.methodName (obj1.metric1)
class A:
def __init__(self, region):
self.region = region
def metric1(self, a, b):
return a*b
def metric2(self, a, b, c):
return self.metric1(a, b) + c
def evaluate(self, metric, a, b, c = None):
if metric == A.metric1:
score = self.metric1(a,b)
elif metric == A.metric2:
score = self.metric2(a,b,c)
return score
obj1 = A('XYZ')
print(obj1.evaluate(A.metric1, a=1, b=2)) # 2
print(obj1.evaluate(A.metric2, a=1, b=2, c=3)) # 5
My approach of writing such class.
class A:
def __init__(self, region, a, b, c=None):
self.region = region
self.a = a
self.b = b
self.c = c
def metric1(self):
return self.a * self.b
def metric2(self):
return A.metric1(self) + self.c
obj1 = A('XYZ', 1, 2, 3)
print(A.metric1(obj1)) # 2
print(A.metric2(obj1)) # 5

Property method in python not returning correct value

I am trying to solve the question in which I am asked to use property method to count the number of times the circles are created . Below is the code for the same.
import os
import sys
#Add Circle class implementation below
class Circle:
counter = 0
def __init__(self,radius):
self.radius = radius
Circle.counter = Circle.counter + 1
def area(self):
return self.radius*self.radius*3.14
def counters():
print(Circle.counter)
no_of_circles = property(counter)
if __name__ == "__main__":
res_lst = list()
lst = list(map(lambda x: float(x.strip()), input().split(',')))
for radius in lst:
res_lst.append(Circle(radius).area())
print(str(res_lst), str(Circle.no_of_circles))
The above code gives correct output for the area but counter should be 3 and instead I am getting below output . Below is the output for input = 1,2,3
[3.14, 12.56, 28.26] <property object at 0x0000024AB3234D60>
I have tried everything but no luck. In the main section of the code no_of_circles is called as Circle.no_of_circles which suggests me that it will use property method of python. But the output is wrong. Please help me find where I am going wrong.
Here is a simple working example using the property function.
Note: It is always a good practice to make an instance of a class(once) and then uses the instance all over your code. Also better to use self.counter instead of Cirlcle.counter. self is Circle.
#Add Circle class implementation below
class Circle:
def __init__(self,value=0):
self._counter = value
def area(self, radius):
return radius*radius*3.14
def add_counter(self, value):
print('add counter')
self._counter += 1
def get_counter(self):
print('get counter')
return self._counter
no_of_circles = property(get_counter, add_counter)
if __name__ == "__main__":
circle = Circle()
area = []
for idx in range(5):
area.append(circle.area(idx))
circle.add_counter(1)
print("number of calls: ", circle.no_of_circles)
print('area:', area)
output(note how get and add counter are called):
add counter
add counter
add counter
add counter
add counter
get counter
number of calls: 5
area: [0.0, 3.14, 12.56, 28.26, 50.24]
str(Circle.no_of_circles) here you're calling the property of a class not an instance of that class i.e a Circle object; the following will work :-
class Circle:
counter = 0
def __init__(self,radius):
self.radius = radius
Circle.counter = Circle.counter + 1
def area(self):
return self.radius*self.radius*3.14
def counters():
print(Circle.counter)
no_of_circles = property(counter)
if __name__ == "__main__":
lst = list(map(lambda x: float(x.strip()), input("Enter radius : ").split(',')))
cir_lst = [Circle(_) for _ in lst]
res_lst = [__.area() for __ in cir_lst]
print(res_lst, cir_lst[-1].counter)

Pass list values into class with a loop in Python

I am trying to pass multiple input entries i as arguments into class Student(). After the last iteration (m), I get a type error. I already tried a for-loop as well, but it didn't work either. Thanks for your help!
class Student():
def __init__(self, d, a, b, c):
self.d = d
self.a = a #name
self.b = b #roll
self.c = c #percentage
return#
def uid(self):
print('UID:', self.d)
def name(self):
print('Name:', self.a)
def roll(self):
print('Roll:', self.b)
def perc(self):
print('Perc:', self.c)
#THIS IS WHAT YOUR INPUT SHOULD LOOK LIKE:
#Peter 405 100
m = input('how many entries? ')
n = 0
while n < int(m):
i = input()
j = i.split()
o = Student(n,*j)
o.uid(), o.name(), o.roll(), o.perc()
n+=1
Student()
The last line - Student() creates an instance of the class without providing any arguments. Hence, Python raises a type error.
Deleting this line (or entering the arguments) will fix the problem.

how to get the updated size of dynamic array in python

How should I edit my code?
import ctypes
import sys
class DynamicArray(object):
def __init__(self):
self.n = 0 #counter
self.capacity = 1
self.A = self.make_array(self.capacity)
def __len__(self):
'''Returns the number of elements'''
b = sys.getsizeof(self.A)
print(b)
return self.n
def __getitem__(self,k):
'''Return elements in array with specified Index'''
if not 0<=k<self.n:
return IndexError('Index out of bounds')
return self.A[k]
def append(self,ele):
'''Add element in the array'''
if self.n==self.capacity:
self._resize(2*self.capacity)
self.A[self.n]=ele
self.n+=1
def _resize(self,new_cap):
B = self.make_array(new_cap)
for k in range(self.n):
B[k]=self.A[k]
self.A = B
self.capacity = new_cap
def make_array(self,new_cap):
'''Make a raw array using ctype module'''
return (new_cap*ctypes.py_object)()
arr = DynamicArray()
arr.append(1)
len(arr)
Output:
80
1
arr.append(1)
len(arr)
Output:
80
2
see https://docs.python.org/3/library/sys.html#sys.getsizeof
from doc:
Return the size of an object in bytes. The object can be any type of
object. All built-in objects will return correct results, but this
does not have to hold true for third-party extensions as it is
implementation specific.
Only the memory consumption directly attributed to the object is
accounted for, not the memory consumption of objects it refers to.
I hope it is clear.

Resources