我们希望在 Python 中设计一个模块/类来实现延迟计算/延迟函数调用。设置这些计算后,我们希望能够确切地识别出答案的由来,并且能够修改函数的输入值并重新计算输出,而无需重新定义中间变量。
我们希望能够尽可能实现以下功能:
>>> a=3
>>> b=5
>>> c=a+b
>>> c
8
>>> a = 6
>>> c
11
并且能够获得如下信息:
>>> c.calculation
'a [ 6 ] + b [ 5 ] = 11'
解决方案
为了实现上述目标,我们可以引入两个类:operable
和 calculation
。
operable
类是一个抽象类,它定义了基本的操作方法,比如加法和乘法。calculation
类表示一个计算,它包含一个操作符和操作数列表。
使用这两个类,我们可以实现延迟计算功能。当我们执行以下代码时:
a = constant(2)
b = constant(3)
c = a + b
d = a * b
变量 c
和 d
将存储 calculation
对象。这些对象包含加法或乘法的操作符,以及操作数列表。当我们访问 c
或 d
的值时,将计算这些值并返回结果。
如果我们随后修改变量 a
和 b
的值,那么 c
和 d
将自动更新其值。这是因为 calculation
类实现了 value
属性,该属性计算并返回计算结果。
使用这种延迟计算方法,我们可以轻松地确定答案的由来,并且可以修改函数的输入值并重新计算输出,而无需重新定义中间变量。
下面是完整的代码实现:
import operator
class operable(object):
def __add__(self,other):
if isinstance(other,operable):
d = calculation()
d.operator = operator.__add__
d.operands = [self,other]
return d
def __mul__(self,other):
if isinstance(other,operable):
d = calculation()
d.operator = operator.__mul__
d.operands = [self,other]
return d
class calculation(operable):
def __init__(self):
self.operands = []
self.operator = None
@property
def value(self):
return reduce(self.operator, [x.value for x in self.operands])
@property
def calculation(self):
return (" %s " % str(self.operator)).join([x.__repr__() for x in self.operands])
def __repr__(self):
return "%d [ %s ] " % ( self.value, self.calculation )
class constant(operable):
def __init__(self, x = 0):
self._value = x
def __repr__(self):
return "%d" %( self.value)
@property
def value(self):
return self._value
@value.setter
def value(self,new_val):
self._value = new_val
def test_1():
a = constant(2)
b = constant(3)
c = a + b
d = a * b
z = a + b + c + d
print "c is",c
print "d is",d
print "z is ",z
b.value = 5
print "c is now",c
print "d is now",d
print "z is now ",z
if __name__ == "__main__":
test_1()
输出结果:
c is 5 [ 2 <built-in function __add__> 3 ]
d is 6 [ 2 <built-in function __mul__> 3 ]
z is 21 [ 2 <built-in function __add__> 3 <built-in function __add__> 5 <built-in function __add__> 6 <built-in function __mul__> 3 ]
c is now 8 [ 2 <built-in function __add__> 5 ]
d is now 10 [ 2 <built-in function __mul__> 5 ]
z is now 29 [ 2 <built-in function __add__> 5 <built-in function __add__> 8 <built-in function __add__> 10 <built-in function __mul__> 5 ]