计算两个 class 实例之间的数值增量
Calculate the delta in numeric values between two class instances
我有一个 Python class 可以执行大量计算。 class 支持各种计算,每个计算可能会或可能不会实际被调用。这是一个例子:
class MyCalc(object):
def __init__(user, query_date, award):
self.user = user
self.query_date = query_date
self.award = award
def balance(self): # this can be subtracted
return self.award.balance
def value(self): # this can be subtracted
if self.user.award_date > self.query_date:
return self.award.value * self.user.multiplier
return 0
def has_multiple_awards(self): # this can not be subtracted
return self.user.awards > 2
def as_pandas_series(self):
return pd.Series({'balance': self.balance(),
'value': self.value(),
'query_date': self.query_date,
'award': self.award,
'user': self.user})
我想要的是计算 class 的两个实例之间的差异。我想出了以下方法,但不确定这种方法是否有任何缺点或者是否有更好的方法?
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()
或者我可以添加装饰器而不使用 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
如有任何反馈,我们将不胜感激。
import operator
class MyCalc(object):
def __init__(self, x=0, y=0, *args):
self.x = x
self.y = y
def calc_x(self):
return self.x * 2
def calc_y(self): # There's about 15 of these calculations
return self.y / 2
class Diff(object):
def __init__(self, a, b):
self.a = a
self.b = b
def _diff(self, func, *args):
getter = operator.attrgetter(func)
closing = getter(self.a)()
opening = getter(self.b)()
return closing - opening
a = MyCalc(50)
b = MyCalc(100)
diff = Diff(a, b)
ret = diff._diff("calc_x")
print ret
>>> -100
你的 Diff
class 对我来说看起来不错,但我仍然不确定这是否是 Pythonic 的。 ;) 我没有看到任何重大缺点,但可以提高效率。
这是 Diff
class 的另一种实现方式。它的效率更高一些,因为它不必在每次 __getattr__
调用时执行查找和两次 operator.attrgetter
调用。相反,它使用 functools.partial
and the built-in getattr
函数缓存属性访问函数。
我还实现了一个简单的 MyCalc
class 用于测试目的。
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)
输出
25
194
59
1172
你说你的 class 支持大约 15 个计算,所有 returning 数值,其中一些可能会或可能不会被调用。
最干净和最 Pythonic 似乎有一个 calc()
方法 returning 向量,即 NumPy 数组(或 Pandas 系列或 DataFrame)。然后客户端代码可以简单地做向量减法:ab_diff = a.calc() - b.calc()
。 np.array 似乎没有必要重新发明轮子,只是根据你所描述的。
如果其中一些计算 rarely-called and/or 的计算成本很高,那么您可以重构为 calc()
和 calc_rare()
。或者,您可以将 kwargs 传递给 calc(..., compute_latlong=False, compute_expensive_stuff=False)
。您可以 return np.NaN
作为您默认不计算的昂贵内容的默认值,以保持向量长度不变。
import numpy as np
#import pandas as pd
class MyCalc(object):
def __init__(self, ...): ...
# (You can either have 15 calculation methods, or use properties.
# It depends on whether any of these quantities are interrelated
# or have shared dependencies, especially expensive ones.)
def calc_q(self): ...
def calc_r(self): ...
def calc_s(self): ...
...
def calc_y(self): ...
def calc_z(self): ...
# One main calc() method for the client. (You might hide the
# other calc_* methods as _calc_*, or else in properties.)
def calc(self):
return np.array([ calc_q(), calc_r(), calc_s(),
... calc_y(), calc_z() ]) # Refactor this as you see fit
if __name__ == '__main__':
# Client is as simple as this
a = MyCalc(...)
b = MyCalc(...)
ab_diff = a.calc() - b.calc()
我有一个 Python class 可以执行大量计算。 class 支持各种计算,每个计算可能会或可能不会实际被调用。这是一个例子:
class MyCalc(object):
def __init__(user, query_date, award):
self.user = user
self.query_date = query_date
self.award = award
def balance(self): # this can be subtracted
return self.award.balance
def value(self): # this can be subtracted
if self.user.award_date > self.query_date:
return self.award.value * self.user.multiplier
return 0
def has_multiple_awards(self): # this can not be subtracted
return self.user.awards > 2
def as_pandas_series(self):
return pd.Series({'balance': self.balance(),
'value': self.value(),
'query_date': self.query_date,
'award': self.award,
'user': self.user})
我想要的是计算 class 的两个实例之间的差异。我想出了以下方法,但不确定这种方法是否有任何缺点或者是否有更好的方法?
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()
或者我可以添加装饰器而不使用 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
如有任何反馈,我们将不胜感激。
import operator
class MyCalc(object):
def __init__(self, x=0, y=0, *args):
self.x = x
self.y = y
def calc_x(self):
return self.x * 2
def calc_y(self): # There's about 15 of these calculations
return self.y / 2
class Diff(object):
def __init__(self, a, b):
self.a = a
self.b = b
def _diff(self, func, *args):
getter = operator.attrgetter(func)
closing = getter(self.a)()
opening = getter(self.b)()
return closing - opening
a = MyCalc(50)
b = MyCalc(100)
diff = Diff(a, b)
ret = diff._diff("calc_x")
print ret
>>> -100
你的 Diff
class 对我来说看起来不错,但我仍然不确定这是否是 Pythonic 的。 ;) 我没有看到任何重大缺点,但可以提高效率。
这是 Diff
class 的另一种实现方式。它的效率更高一些,因为它不必在每次 __getattr__
调用时执行查找和两次 operator.attrgetter
调用。相反,它使用 functools.partial
and the built-in getattr
函数缓存属性访问函数。
我还实现了一个简单的 MyCalc
class 用于测试目的。
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)
输出
25
194
59
1172
你说你的 class 支持大约 15 个计算,所有 returning 数值,其中一些可能会或可能不会被调用。
最干净和最 Pythonic 似乎有一个 calc()
方法 returning 向量,即 NumPy 数组(或 Pandas 系列或 DataFrame)。然后客户端代码可以简单地做向量减法:ab_diff = a.calc() - b.calc()
。 np.array 似乎没有必要重新发明轮子,只是根据你所描述的。
如果其中一些计算 rarely-called and/or 的计算成本很高,那么您可以重构为 calc()
和 calc_rare()
。或者,您可以将 kwargs 传递给 calc(..., compute_latlong=False, compute_expensive_stuff=False)
。您可以 return np.NaN
作为您默认不计算的昂贵内容的默认值,以保持向量长度不变。
import numpy as np
#import pandas as pd
class MyCalc(object):
def __init__(self, ...): ...
# (You can either have 15 calculation methods, or use properties.
# It depends on whether any of these quantities are interrelated
# or have shared dependencies, especially expensive ones.)
def calc_q(self): ...
def calc_r(self): ...
def calc_s(self): ...
...
def calc_y(self): ...
def calc_z(self): ...
# One main calc() method for the client. (You might hide the
# other calc_* methods as _calc_*, or else in properties.)
def calc(self):
return np.array([ calc_q(), calc_r(), calc_s(),
... calc_y(), calc_z() ]) # Refactor this as you see fit
if __name__ == '__main__':
# Client is as simple as this
a = MyCalc(...)
b = MyCalc(...)
ab_diff = a.calc() - b.calc()