使用操作员模块自动构建魔术方法

时间:2017-09-22 20:39:50

标签: python python-3.x

我想编写一个包含表达式的类,以便以后进行评估。例如,以下类可以包含涉及加法和乘法的表达式。

import operator as op

class Expr(object):
    def __init__(self, func = lambda x: x):
        self.expr = func

    def __call__(self, x):
        return self.expr(x)

    def __sub__(self, other):
        return Expr(lambda x: op.sub(self.expr(x), other))

    def __mul__(self, other):
        return Expr(lambda x: op.mul(self.expr(x), other))

    def __rsub__(self, other):
        # Subtraction is not commutative -> order matters
        return Expr(lambda x: op.sub(other, self.expr(x)))

    def __rmul__(self, other):
        return Expr(lambda x: op.mul(other, self.expr(x)))

我们可以使用这个类来延迟表达式的评估,例如

>>> e1 = Expr()
>>> e2 = 5*e1 - 4
>>> e2(3)
11

请注意,评估顺序对于减法等非交换操作非常重要(请参阅下面5 - e1的评估)。

>>> es = (2*e1, e1*3, e1 - 3, 4 - e1, 2*e2-3)
>>> [expr(5) for expr in es]
[10, 15, 2, -1, 39]

问题在于我想为几乎所有操作符实现这样的方法,并且明确地这样做会很烦人并明显违反DRY原则。

问题:如何使用operator模块中的函数自动执行所有算术运算符和布尔运算符的过程?

可接受的解决方案将实施以下操作:-*,否定(即-x),==>。我最感兴趣的是Python 3的解决方案,但便携式解决方案将是一个奖励!

1 个答案:

答案 0 :(得分:1)

这是工作代码:

import operator as op

class Expr(object):
    def __init__(self, func=lambda x: x):
        self.expr = func

    def __call__(self, x):
        return self.expr(x)


def factory(name):
    def operator(self, other):
        return Expr(lambda x: getattr(op, name)(self.expr(x), other))
    def roperator(self, other):
        return Expr(lambda x: getattr(op, name)(other,self.expr(x)))
    return operator,roperator


for n in ["add", "sub", "mul","truediv"]:
    op,rop = factory(n)
    setattr(Expr, "__{}__".format(n), op)
    setattr(Expr, "__r{}__".format(n), rop)

e1 = Expr()
e2 = 2*e1 + 5
print(e2(3))