2013-07-16 54 views
2

我在問如何讓「關閉」以重載and運算符的建議。鏈接比較(重載不可重載的「和」運算符)

import operator 


OP = { operator.ge: ">=", operator.le: "<=" } 


class Expression(object): 
    def __init__(self, left, right, op): 
     self.left = left 
     self.right = right 
     self.op = op 

    def __le__(self, other): 
     return Expression(self, other, operator.le) 

    def __ge__(self, other): 
     return Expression(self, other, operator.ge) 

    def __str__(self): 
     return "(%s %s %s)" % (self.left, OP[self.op], self.right) 

    def __repr__(self): 
     return "<Expression: %s %s %s>" % (self.left, self.op, self.right) 


class Variable(Expression): 
    def __init__(self, name): 
     self.name = name 

    def __str__(self): 
     return self.name 

    def __repr__(self): 
     return "<Variable: %s>" % self.name 


def _and(left, right): 
    return (left, right) 

print 1 <= Variable("x") <= 3 
print _and(1 <= Variable("x"), Variable("x") <= 3) 

上面的例子打印::一個代碼示例以我在做什麼暗示

(x <= 3) 
(<Expression: x <built-in function ge> 1>, <Expression: x <built-in function le> 3>) 

按照Python docs表達1 <= a <= 2轉化爲1 <= a and a <= 2,所以我猜,在我的示例1 <= Variable("x")的計算結果爲True,因此表達式返回值Variable("x") <= 3。我需要一種方法分別得到兩個表達式(1 <= aa <= 2),並且最好不用兩次寫出中間表達式(就像我用_和函數做的那樣),因爲中間表達式可能相當複雜並且有兩次(I意識到我可以將它保存到一個變量並使用它,但這也是不太可讀的)。根據this SE postand運算符不能被重載,所以我問的是這是否可以完成,然後如何,或者如果我不得不求助於分裂兩個比較(指定中間表達式兩次)。任何建議在正確的方向表示讚賞!謝謝。

可能相關:

編輯: 那麼我現在主要做的是一個linear program寫出的限制,我的代碼,以便相關部門目前是這個樣子:

model.add_constr(a <= b) 
model.add_constr(b <= c) 
# now i could alter add_constr to support either a tuple or two arguments enabling: 
model.add_constr(a <= b, b <= c) 
model.add_constr((a <= b, b <= c)) 
# but most pleasing would be if I could do 
model.add_constr(a <= b <= c) 
# that would return for example a two tuple that could be interpreted appropriately by 
# add_constr() 

回答

2

它看起來像要延遲評估或靜態分析一個類似Python的表達式。你有沒有考慮過使用抽象語法樹? Python可以使用ast標準庫模塊中的工具解析和不評估表達式。請參閱http://docs.python.org/2/library/ast.htmlhttp://eli.thegreenplace.net/2009/11/28/python-internals-working-with-python-asts/。您可以將Python表達式表示爲一個數據結構,而不用試圖佔用每個運算符,您可以隨心所欲地執行任何操作。您可以對樹進行修改,然後執行結果,或者將樹轉換爲您自己的ExpressionVariable類。

例如,ast表示作爲表達式和比較運算符的任意長列表的比較鏈(請參閱Compare表達式類型)。這是如何實現鏈接的。

編輯:下面是一個例子用法:

>>> import ast 
>>> x = ast.parse("2 + 2") 
>>> print ast.dump(x) 
Module(body=[Expr(value=BinOp(left=Num(n=2), op=Add(), right=Num(n=2)))]) 
>>> eval(compile(ast.Interactive(body=[x.body[0]]), "fakefile", "single")) 
4 

在你的情況,你可能不會跟進到實際上是讓Python的計算表達式,因爲你只想使用Python作爲表達式解析器,而不是口譯員。 (這就是您的ExpressionVariable符號樹實際上正在做的事情。)您將解釋可能表達式樹的子集作爲指令傳遞給model。也就是說,您可以處理您感興趣的Python子集:符號(變量),比較運算符,邏輯運算符。其餘的可以提高SyntaxErrorNotImplementedError或任何你想用來通知你的用戶,他們正試圖做的東西以外的實施子集。

+0

這聽起來很有希望。我稍後再檢查一下:)。 – karihre

+0

做了一些閱讀,但有點困惑。我將如何「推遲」這些表達式的評估?根據我的理解,我基本上必須通過一個不同的腳本來運行我的python腳本(比如'$ python transform.py original.py'),它會查看腳本源並在評估代碼之前更改AST的腳本?或者將表達式作爲字符串傳遞給「錯誤」解釋它們的函數?我可以忽略一些東西嗎 – karihre

+0

我希望我能回答你所問的問題:你通過AST解釋的表達式必須被引用,或者通過文字引用來評估(「我的表達式」),或者通過轉換整個外部文件。這在Lisp中基本上就像'(quote(stuff ...))'。 「錯誤」解釋的Python代碼不能與其他Python代碼自由混合。我會給我的答案添加一個例子。 –

0

對於純粹的語法解決方案,您可以簡單地將括號放在其中一個比較中,以打破Python的運算符鏈接:(a <= b) <= c

雖然我不確定它有多大意義。也就是說,如果你使用正常值來做這件事,你通常會得到一個無意義的結果(或者是Python 3中的錯誤)。它可能會混淆其他人閱讀你的代碼(或者你自己,從現在開始)。

我懷疑有一個更好的解決方案是按照你的想法去做,並堅持簡單的比較當你需要表達一個雙端約束時,使用兩個單端約束。如果在中間需要複雜的值,請嘗試將其保存在變量中,而不是在每個表達式中重新計算:

b_expr = b**4 + 3*b**2 - 4*x - 100 
model.add_constr(a <= b_expr, b_expr <= c)