Python中使用方法链进行延迟计算

时间:2018-05-24 17:22:38

标签: 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 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中做这样的事情?

4 个答案:

答案 0 :(得分:2)

就个人而言,我会.add()等将操作符和操作数推送到列表中,然后让.compute()遍历列表,计算答案。

通过将每个运算符return 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

答案 1 :(得分:0)

正如@Rob指出的那样,您需要一些方法来存储运算符,以便可以正确使用最终的compute方法。此解决方案使用__add____sub__,并使用装饰器来存储运算符。但请注意,保持已推送到堆栈的值的运行总数会更有效:

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

答案 2 :(得分:0)

这是一种基于字符串的方法,需要很少的智力。

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())

答案 3 :(得分:0)

哇,你们快点!

这是另一个也有堆栈,但操纵结果列表:

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]