2017-09-22 41 views
0

我想編寫一個將包含表達式的類以供以後評估。例如,以下類可以保存涉及加法和乘法的表達式。使用運算符模塊自動執行魔法方法

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的解決方案感興趣,但一個便攜式解決方案將是一個獎金!

+0

遍歷運營商和他們的名字和使用SETATTR()爲您創造類的功能。 – wwii

+0

考慮讓你的'Expr'存儲'(函數,args或(),kwargs或{})'分開,而不僅僅是一個可調用的。 – o11c

回答

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)) 
+0

我認爲'__radd__'需要翻轉其他和調用'self.expr'。正確? – yardsale8

+0

@ yardsale8正確。我添加了它。 – MegaIng

+0

原始代碼中有一個錯誤('或'是限制名稱)。不幸的是,我的編輯導致了另一個錯誤(重用了'op'這個名字)。如果在循環中的所有引用中將op,rop更改爲o,ro,我們會得到正確的解決方案。謝謝您的幫助! – yardsale8