Johan Johan - 1 year ago 49
Python Question

Calculate the difference of calculations between two class instances

I have a Python class that performs a bunch of calculations. Here is an example:

class MyCalc(object):
def calc_x(self):
return some_calc

def calc_y(self): # There's about 15 of these calculations
return some_calc


What I want is to calculate the difference between two instances of the class. I've come up with the following approach, but not sure if this method has any drawbacks or maybe there's a better way?

class Diff(object):
def __init__(self, a, b):
self.a = a
self.b = b

def __getattr__(self, attr):
getter = operator.attrgetter(attr)
closing = getter(self.a)()
opening = getter(self.b)()
return closing - opening

a = MyCalc()
b = MyCalc()
diff = Diff(a, b)
print(diff.calc_x) # calculate a.calc_x() - b.calc_x()


Alternatively I can add a decorator and don't use the Diff class:

def differance(func):
def func_wrapper(self):
return func(self) - func(self.b)
return func_wrapper


class MyCalc(object):
@difference
def calc_x(self):
return some_calc

@difference
def calc_y(self):
return some_calc


Any feedback will be appreciated.

Answer Source

Your Diff class looks fine to me, but I'm still undecided whether this is Pythonic or not. ;) I don't see any major drawbacks, but it can be made more efficient.

Here's an alternative implementation of the Diff class. It's a little more efficient since it doesn't have to do a lookup and two calls of operator.attrgetter on each __getattr__ call. Instead, it caches the attribute accessing functions using functools.partial and the built-in getattr function.

I've also implemented a simple MyCalc clas for testing purposes.

from functools import partial

class MyCalc(object):
    def __init__(self, u, v):
        self.u = u
        self.v = v

    def calc_x(self):
        return self.u + self.v

    def calc_y(self):
        return self.u * self.v

class Diff(object):
    def __init__(self, a, b):
        self.geta = partial(getattr, a)
        self.getb = partial(getattr, b)

    def __getattr__(self, attr):
        closing = self.geta(attr)()
        opening = self.getb(attr)()
        return closing - opening


a = MyCalc(10, 20)
b = MyCalc(2, 3)

diff = Diff(a, b)
print(diff.calc_x)
print(diff.calc_y)

a.u, a.v = 30, 40
b.u, b.v = 4, 7
print(diff.calc_x)
print(diff.calc_y)

output

25
194
59
1172
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download