Python中带方法链接的延迟计算
假设我有一门课:Python中带方法链接的延迟计算,python,Python,假设我有一门课: class MATH(object): def __init__(self): self.results = [0, 1, 2] def add(self, value): # Add amount 'value' to every element in the results list def minus(self, value): # Subtract amount 'value' from eve
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
def add(self, value):
# Add amount 'value' to every element in the results list
def minus(self, value):
# Subtract amount 'value' from every element in the results list
def compute(self):
# Perform computation
有没有一种方法可以做到:
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
m.compute() # This would actually run the computations in order
在python中如何执行类似的操作?我个人会使用
.add()
,等等,将运算符和操作数推到列表上,然后让.compute()
遍历列表,边走边计算答案
通过让每个操作符返回self
作为其最终指令,可以轻松完成操作符链接
例如:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
self.operations = []
def add(self, value):
# Add amount 'value' to every element in the results list
self.operations.append(('+', value))
return self
def minus(self, value):
# Subtract amount 'value' from every element in the results list
self.operations.append(('-', value))
return self
def compute(self):
results = []
for x in self.results:
for op, value in self.operations:
if op == '+':
x += value
elif op == '-':
x -= value
results.append(x)
return results
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
print(m.compute()) # This would actually run the computations in order
就我个人而言,我会让
.add()
等将运算符和操作数推到一个列表上,然后让.compute()
遍历列表,一边计算答案
通过让每个操作符返回self
作为其最终指令,可以轻松完成操作符链接
例如:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
self.operations = []
def add(self, value):
# Add amount 'value' to every element in the results list
self.operations.append(('+', value))
return self
def minus(self, value):
# Subtract amount 'value' from every element in the results list
self.operations.append(('-', value))
return self
def compute(self):
results = []
for x in self.results:
for op, value in self.operations:
if op == '+':
x += value
elif op == '-':
x -= value
results.append(x)
return results
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
print(m.compute()) # This would actually run the computations in order
正如@Rob指出的,您需要某种方法来存储操作符,以便正确使用最终的
compute
方法。此解决方案使用\uuuuuuuuuuuuuuuuuuuu
和\uuuuuuuuuuuuuuuuuuuuuuuuuuuu
以及一个装饰器来存储操作符。但是,请注意,保持已推送到堆栈中的值的运行总数将更加有效:
import operator as op
from collections import deque
def operator(f):
def wrapper(cls, _):
cls.operators.append(f.__name__.replace('__', ''))
return f(cls, _)
return wrapper
class Math:
def __init__(self):
self.stack = []
self.operators = deque()
@operator
def __sub__(self, _val):
self.stack.append(_val)
return self
@operator
def __add__(self, _val):
self.stack.append(_val)
return self
def compute(self):
_result = 0
while self.stack:
a, *c = self.stack
_result = getattr(op, self.operators.popleft())(_result, a)
self.stack = c
return _result
m = Math()
m1 = m + 5 - 2 + 7
print([m1.stack, m1.operators])
print(m1.compute())
输出:
[[5, 2, 7], ['add', 'sub', 'add']]
10
正如@Rob指出的,您需要某种方法来存储操作符,以便正确使用最终的
compute
方法。此解决方案使用\uuuuuuuuuuuuuuuuuuuu
和\uuuuuuuuuuuuuuuuuuuuuuuuuuuu
以及一个装饰器来存储操作符。但是,请注意,保持已推送到堆栈中的值的运行总数将更加有效:
import operator as op
from collections import deque
def operator(f):
def wrapper(cls, _):
cls.operators.append(f.__name__.replace('__', ''))
return f(cls, _)
return wrapper
class Math:
def __init__(self):
self.stack = []
self.operators = deque()
@operator
def __sub__(self, _val):
self.stack.append(_val)
return self
@operator
def __add__(self, _val):
self.stack.append(_val)
return self
def compute(self):
_result = 0
while self.stack:
a, *c = self.stack
_result = getattr(op, self.operators.popleft())(_result, a)
self.stack = c
return _result
m = Math()
m1 = m + 5 - 2 + 7
print([m1.stack, m1.operators])
print(m1.compute())
输出:
[[5, 2, 7], ['add', 'sub', 'add']]
10
这里有一个基于字符串的方法,它需要很少的脑力
class Math:
def __init__(self):
self.stack = '0'
@staticmethod
def wrap(expr):
return '(' + expr + ')'
def _op(self, other, op):
self.stack = ' '.join([Math.wrap(self.stack), op, str(other)])
def add(self, other):
self._op(other, '+')
return self
def mul(self, other):
self._op(other, '*')
return self
def compute(self):
return eval(self.stack)
m = Math()
print(m.add(2).mul(3).compute())
这里有一个基于字符串的方法,它需要很少的脑力
class Math:
def __init__(self):
self.stack = '0'
@staticmethod
def wrap(expr):
return '(' + expr + ')'
def _op(self, other, op):
self.stack = ' '.join([Math.wrap(self.stack), op, str(other)])
def add(self, other):
self._op(other, '+')
return self
def mul(self, other):
self._op(other, '*')
return self
def compute(self):
return eval(self.stack)
m = Math()
print(m.add(2).mul(3).compute())
哇,你们真快 下面是另一个使用堆栈的方法,但操作结果列表:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
self.stack = []
def add(self, value):
self.stack.append(value)
return self
def minus(self, value):
self.stack.append(-value)
return self
def compute(self):
for s in self.stack:
for index, _ in enumerate(self.results):
self.results[index] += s
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
m.compute() # This would actually run the computations in order
print m.results
[10,11,12]哇,你们跑得真快 下面是另一个使用堆栈的方法,但操作结果列表:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
self.stack = []
def add(self, value):
self.stack.append(value)
return self
def minus(self, value):
self.stack.append(-value)
return self
def compute(self):
for s in self.stack:
for index, _ in enumerate(self.results):
self.results[index] += s
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
m.compute() # This would actually run the computations in order
print m.results
[10、11、12]因为您至少必须始终存储运算符和操作数,对于任何不是最密集的计算,所增加的开销可能比立即进行计算要大。是的,但是OP特别要求操作被延迟…这就是为什么我不想在这里做任何事情,但我认为OP应该考虑是否有另一种解决方案可以解决他的问题,而不是延迟计算。如果没有更多的背景,我不能直接说这是一个XY问题,但听起来确实像。这个问题可能有一个XY组件,但这也是一个完全合理的建模符号表达式的方法:类似于
m.add('x')。减(2)
,然后是m.compute(x=5)
。因为您将始终至少必须存储运算符和操作数,对于任何不是最密集的计算,所增加的开销很可能会大于立即执行计算。是的,但OP特别要求延迟操作…这就是为什么我不想在这里做任何事,但我认为OP应该考虑是否有其他解决方案可以解决他的问题,而不是延迟计算。如果没有更多的背景,我不能直接说这是一个XY问题,但听起来确实像。这个问题可能有一个XY组件,但这也是一个非常合理的建模符号表达式的方法:类似于m.add('x')。减(2)
,然后是m.compute(x=5)
。