Calculating the difference between the output of two class objects - python

I have created two class objects that retrieve information from a database and store them in pandas in order for me to use the data science libraries. They both return values that I display in a Django template. I want to create a third value that is just the calculated difference of the first two and also display that in the Django template.
First class object:
class IntDailyNumbers (object):
def __init__(self, begin_date, end_date, store=None):
self.begin_date = begin_date
self.end_date = end_date
self.store = store
self.int_daily_numbers = pd.DataFrame(list(gapayment.objects.values('Trans_Store', 'Fee_Pd', 'Trans_date')))
self.int_daily_numbers['Fee_Pd'] = pd.to_numeric(self.int_daily_numbers['Fee_Pd'])
self.int_daily_numbers['Trans_date'] = pd.to_datetime(self.int_daily_numbers['Trans_date'])
self.sum_int_daily_numbers = np.sum(self.int_daily_numbers[(self.int_daily_numbers['Trans_date'] >=self.begin_date) &
(self.int_daily_numbers['Trans_date'] <= self.end_date) &
(self.int_daily_numbers['Trans_Store'] == self.store.store_number)])
def get_sum_int_daily_numbers(self):
sum_intdailynumbers = self.sum_int_daily_numbers['Fee_Pd']
sum_intdailynumbers = round(sum_intdailynumbers.astype(float), 3)
return sum_intdailynumbers
def __str__(self):
return self.get_sum_int_daily_numbers()
Second Class Object:
class IntDailyGoals (object):
def __init__(self, begin_date, end_date, store=None):
self.begin_date = begin_date
self.end_date = end_date
self.store = store
#print(self.begin_date, self.end_date, self.store.store_number)
self.int_mnth_goal = pd.DataFrame(list(StoreGoalsInput.objects.values('store_number',
'interest',
'date')))
self.int_mnth_goal['interest'] = pd.to_numeric(self.int_mnth_goal['interest'])
self.int_mnth_goal['date'] = pd.to_datetime(self.int_mnth_goal['date'])
self.mnth_goal_int =self.int_mnth_goal[(self.int_mnth_goal['date'] >= self.begin_date) &
(self.int_mnth_goal['date'] <= self.end_date) &
(self.int_mnth_goal['store_number'] == self.store.store_number)]
self.mnth_goal_int= self.mnth_goal_int['interest']
self.tot_workingdays = np.busday_count(np.datetime64(self.begin_date),
np.datetime64(self.end_date),
weekmask='Mon Tue Wed Thu Fri Sat')
self.div_intmnthgoal_workingdays = round(np.divide(self.mnth_goal_int, self.tot_workingdays),2)
def get_div_goalsint_wdays(self):
div_goalsint_wdays = self.div_intmnthgoal_workingdays.tolist()[0]
return div_goalsint_wdays
def __str__(self):
return self.get_div_goalsint_wdays()
I believe I need to make a third class for the difference calculation but I cannot figure out how to pass the returns of the first two.

How I understand your question, it has nothing to do with django, but with passing objects from one class to another. Here are two simple solutions, given by class C and class D.
First lets define a minimal example of your two classes. Both have a method, that does something and returns something.
class A:
def foo(self):
print('foo')
return 'foo'
class B:
def bar(self):
print('bar')
return 'bar'
Solution 1: We create a third class, that has an instance of type A and an instance of type B as member variable.
# Contains a class instance of A and B and baz() accesses their methods.
class C:
def __init__(self, a, b):
self.a = a
self.b = b
def baz(self):
self.a.foo()
self.b.bar()
You can use this class with:
# main
a = A()
b = B()
c = C(a,b)
c.baz()
Solution 2: We simply pass the two return values to the function qux(). This function can also be part of a class, if you want it to be.
class D:
def qux(self, res_a, res_b):
print(res_a, res_b)
Here we can use qux() in the following way
# main
a = A()
b = B()
d = D()
d.qux(a.foo(),b.bar())
Since there was some confusion about inheritance. You can also inherit the methods. Don't confuse this with Solution 1. And I don't advise to use inheritance here. The idea of inheritance is, that a child class object is-a parent-class object, like a square is-a rectangle. And that is not what you want.
class E(A,B):
def foobar(self):
self.foo()
self.bar()
Usage from main:
e = E()
e.foobar()

Related

Is there a way to pass a function call to an inner object?

Is there a way in python to pass a function call to an inner object, maybe through a decorator or wrapper? In the example below, class A holds a list of class B objects, and one of the class B objects is selected as the active object. I want class A to function as a passthrough, just identifying which of the class B objects that the call goes to. However, class A doesn't know what type of class it is going to hold beforehand, so I can't just add a set_var function to class A. It has to work for any generic function that class B has. It will only have one type of class in its objects list, so it could take class B as an input when it is instantiated and dynamically create functions, if that's a possibility. The client wouldn't know whether it's dealing with class A or class B. The code below is as far as I got.
class A:
def __init__(self):
self.objects = []
self.current_object = 0
def add_object(self, object):
self.objects.append(object)
class B:
def __init__(self):
self.var = 10
def set_var(self, new_var):
self.var = new_var
a_obj = A()
b_obj1 = B()
b_obj2 = B()
a_obj.add_object(b_obj1)
a_obj.add_object(b_obj2)
a_obj.set_var(100)
You could use the generic __getattr__ to delegate to the wrapped object.
class A:
def __init__(self):
self.objects = []
self.current_object = 0
def add_object(self, obj):
self.objects.append(obj)
self.current_object = obj
def __getattr__(self, name):
return getattr(self.current_object, name)
class B:
def __init__(self):
self.var = 10
def set_var(self, new_var):
self.var = new_var
a_obj = A()
b_obj1 = B()
b_obj2 = B()
a_obj.add_object(b_obj1)
a_obj.add_object(b_obj2)
a_obj.set_var(100)
print(b_obj2.var)
That will print "100".
You will still get an AttributeError if the wrapped object doesn't have the expected method.
It was interesting to look at this, it is intentionally rough but it does indeed allow you to call one the B instance's set_var methods.
The code below uses sets as a quick and dirty way to see the difference in callable methods, and if there is; it sets the attribute based on that name. Binding the method to the A instance.
This would only bind set_var once from the first object given.
def add_object(self, object):
self.objects.append(object)
B_methods = set([m for m in dir(object) if callable(getattr(object, m))])
A_methods = set([m for m in dir(self) if callable(getattr(self, m))])
to_set = B_methods.difference(A_methods)
for method in to_set:
setattr(self, method, getattr(object, method))

Store instance of class A in instance of class B

I have a question which is more regarding OOP in general rather than python specific.
Is ist possible to store instances of ClassA in instance of ClassB without a specific method, i.e. by some kind of inheritance.
Example: let's say I have one Model class and one Variable class
class Model():
def __init__(self):
self.vars = []
def _update_vars(self,Variable):
self.vars.append(Variable)
class Variable(Model):
def __init__(self,**kwargs):
self.__dict__.update(kwargs)
Is it now possible to call _update_vars whenever an instance of variable is being created.
So if I do something like this:
mdl = Model()
varA = Variable(...)
varB = Variable(...)
that mdl.vars would now include varA and varB.
I know that I could easily do this by passing the variables as an argument to a "public" method of Model. So I am not looking for
mdl.update_vars(varA)
So my two questions are:
is this possible?
if yes: would this very non-standard OOP programming?
Thanks for your help!
That's not how class inheritance is supposed to work. You only want to inherit something if the child class is going to make use of a good amount of the attributes/methods within the parent class. If the child class has a markedly different structure it should be a class of its own.
In either case, as mentioned by #jasonharper, at some point you would need to give direction as to which Variable instance belongs in which Model instance, so you're likely to end up with something like these:
varA = Variable(mdl, ...)
# or this
mdl.varA = Variable(...)
With the first way, you would maintain the method on your Variable class:
class Foo:
def __init__(self):
self.vars = []
class Bar:
def __init__(self, foo_instance, **kwargs):
foo_instance.vars.append(self)
f = Foo()
b = Bar(f, hello='hey')
f.vars
# [<__main__.Bar object at 0x03F6B4B0>]
With the second way, you can append the Variable instances into a list each time it's added:
class Foo:
def __init__(self):
self.vars = []
def __setattr__(self, name, val):
self.__dict__.update({name: val})
if not name == 'vars': # to prevent a recursive loop
self.vars.append(val)
f = Foo()
f.vars
# []
f.a = 'bar'
f.vars
# ['bar']
Of course, an easier way would be to just look directly into the __dict__ each time you want vars:
class Bar:
#property
def vars(self):
# Or you can return .items() if you want both the name and the value
return list(self.__dict__.values())
b = Bar()
b.a = 'hello'
b.vars
# ['hello']
Both of these will work the same even if you assigned the attributes with your own class instances.
You can use super() for this and pass the instance to the parent
class Model():
vars = []
def __init__(self, other=None):
if other:
self.vars.append(other)
class Variable(Model):
def __init__(self, a):
self.a = a
super().__init__(self)
mdl = Model()
varA = Variable(3)
varB = Variable(4)
print(mdl.vars)

get a return from a function in another class

I want to get a return value, which changes the value due to an triggered event.
like so:
class A:
def __init__(self):
self.ev_nearby = 0
def changeValue(self):
self.ev_nearby = 1
return self.ev_nearby
# I want this value in class B
def getChangedValue(self):
return self.ev_nearby
def logic(self):
while(somethingHappens) {
self.changeValue()
}
# logic is called in another class
class B:
A = A()
# I want the value here like
valueFromA = A.getChangedValue()
The reason of the while is because I need both values dynamically in a server.
But until now, my valueFromA in class B remains still 0, triggered or not triggered.
It seems that .logic() is called on another instance of the object than the one you are trying to retrieve the value from. To retrieve the value from the same instance you can pass it as a variable in the scope of the other class. For more information look into the basics of Object Oriented Programming (in Python)
Below I have written a small example of how this can be achieved:
class A:
def __init__(self):
self.ev_nearby = 0
def changeValue(self):
self.ev_nearby = 1
return self.ev_nearby
# I want this value in class B
def getChangedValue(self):
return self.ev_nearby
def logic(self):
while(somethingHappens) {
self.changeValue()
}
# logic is called in another class
class B:
# I want the value here like
def getValueFromA(self, A):
valueFromA = A.getChangedValue()
return valueFromA
class C:
A = A()
A.logic()
B = B()
B.getValueFromA(A)

Class Attributes VALUES to a list

I have a simple python class that consists of some attributes and some methods.What i need is to make a list out of the class attributes ( only ! )
Class A():
def __init__(self, a=50, b="ship"):
a = a
b = b
def method1():
.....
I want to have a list :
[50, "ship"]
Another solution, possibly more generic, is:
def asList(self):
[value for value in self.__dict__.values()]
Full example with correct syntax:
class A:
def __init__(self, a=50, b="ship"):
self.a = a
self.b = b
def as_list(self):
return [value for value in self.__dict__.values()]
a = A()
print a.as_list()
output:
[50, 'ship']
def asList(self):
return [a,b,....] # will create a new list on each call
Unless you also create an __init__(...) or factory methods or something alike for your class that decomposes this list you wont be able to create a new object back from the list.
See how-to-overload-init-method-based-on-argument-type

Apply a function to all instances of a class

I am looking for a way to apply a function to all instances of a class. An example:
class my_class:
def __init__(self, number):
self.my_value = number
self.double = number * 2
#staticmethod
def crunch_all():
# pseudocode starts here
for instances in my_class:
instance.new_value = instance.my_value + 1
So the command my_class.crunch_all() should add a new attribute new_value to all existing instances. I am guessing I will have to use #staticmethod to make it a "global" function.
I know I could keep track of the instances that are being defined by adding something like my_class.instances.append(number) in __init__ and then loop through my_class.instances, but I had no luck so far with that either. Also I am wondering if something more generic exists. Is this even possible?
Register objects with the class at initialisation (i.e. __init__) and define a class method (i.e. #classmethod) for the class:
class Foo(object):
objs = [] # registrar
def __init__(self, num):
# register the new object with the class
Foo.objs.append(self)
self.my_value = num
#classmethod
def crunch_all(cls):
for obj in cls.objs:
obj.new_value = obj.my_value + 1
example:
>>> a, b = Foo(5), Foo(7)
>>> Foo.crunch_all()
>>> a.new_value
6
>>> b.new_value
8

Categories