使用eval()
可能不是一個好主意,但如果你堅持(Python 3中):
call = lambda f: lambda *args: f(*args)
flip = lambda f: lambda *args: f(*reversed(args))
class Expression:
def __repr__(self):
return '{}({})'.format(type(self).__name__, self)
class BinaryExpression(Expression):
def __init__(self, left, right):
self.left = promote(left)
self.right = promote(right)
def __str__(self):
return '({} {} {})'.format(self.op, self.left, self.right)
class Variable(Expression):
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class Number(Expression):
def __init__(self, value):
self.value = int(value)
def __str__(self):
return str(self.value)
class Multiplication(BinaryExpression):
op = '*'
class Addition(BinaryExpression):
op = '+'
class Smaller(BinaryExpression):
op = '<'
class Greater(BinaryExpression):
op = '>'
class SmallerOrEqual(BinaryExpression):
op = '<='
class GreaterOrEqual(BinaryExpression):
op = '>='
Expression.__mul__ = call(Multiplication)
Expression.__rmul__ = flip(Multiplication)
Expression.__add__ = call(Addition)
Expression.__radd__ = flip(Addition)
Expression.__lt__ = call(Smaller)
Expression.__gt__ = call(Greater)
Expression.__le__ = call(SmallerOrEqual)
Expression.__ge__ = call(GreaterOrEqual)
def promote(item):
if isinstance(item, str):
return Variable(item)
elif isinstance(item, int):
return Number(item)
else:
return item
class LpVariable:
def __init__(self, name, x, y, z):
self.name = name
self.x = x
self.y = y
self.z = z
def __str__(self):
return 'LpVariable({}, {}, {}, {})'.format(
self.name,
self.x,
self.y,
self.z,
)
__repr__ = __str__
LpContinuous = 'LpContinuous'
class ExpressionVisitor:
def visit(self, node):
return getattr(self, 'visit_' + type(node).__name__)(node)
class LpTransformer(ExpressionVisitor):
def visit_Variable(self, node):
return LpVariable(node.name, None, None, LpContinuous)
def visit_Number(self, node):
return node.value
def visit_Multiplication(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_Addition(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_Smaller(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_Greater(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_SmallerOrEqual(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_GreaterOrEqual(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
class Evaluator(ExpressionVisitor):
def __init__(self, **env):
self.env = env
def visit_Variable(self, node):
return self.env[node.name]
def visit_Number(self, node):
return node.value
def visit_Multiplication(self, node):
return self.visit(node.left) * self.visit(node.right)
def visit_Addition(self, node):
return self.visit(node.left) + self.visit(node.right)
def visit_Smaller(self, node):
return self.visit(node.left) < self.visit(node.right)
def visit_Greater(self, node):
return self.visit(node.left) > self.visit(node.right)
def visit_SmallerOrEqual(self, node):
return self.visit(node.left) <= self.visit(node.right)
def visit_GreaterOrEqual(self, node):
return self.visit(node.left) >= self.visit(node.right)
class Namespace(dict):
def __missing__(self, key):
value = self[key] = Variable(key)
return value
def main():
constraints = '2*a + 3*b <= c'
namespace = Namespace()
tree = eval(constraints, {}, namespace)
print('AST in prefix notation:', tree)
print()
print('Namespace:', namespace)
print()
print('LP-Transformed tree:')
import pprint
pprint.pprint(LpTransformer().visit(tree))
print()
print('Evaluated with a=3, b=5, c=10:')
pprint.pprint(Evaluator(a=3, b=5, c=10).visit(tree))
print()
print('Evaluated with a=3, b=5, c=100:')
pprint.pprint(Evaluator(a=3, b=5, c=100).visit(tree))
if __name__ == '__main__':
main()
結果:
AST in prefix notation: (<= (+ (* 2 a) (* 3 b)) c)
Namespace: {'a': Variable(a), 'c': Variable(c), 'b': Variable(b)}
LP-Transformed tree:
['<=',
['+',
['*', 2, LpVariable(a, None, None, LpContinuous)],
['*', 3, LpVariable(b, None, None, LpContinuous)]],
LpVariable(c, None, None, LpContinuous)]
Evaluated with a=3, b=5, c=10:
False
Evaluated with a=3, b=5, c=100:
True
的LpVariable
類顯然是一個樣機。此外,LpTransformer
課程應該生產一些紙漿可用的東西。只需相應地更改visit_*
方法。
數字都是int
s,你可能不想要。您應該添加float
和/或將所有數字轉換爲decimal.Decimal
。
而不是使用eval()
我可能會寫一個真正的解析器,也許用pyparsing,或者,我喜歡這樣的東西,Parcon。
你現在怎麼從終端獲取輸入? – munk
我首先輸入整個字符串,然後你必須檢查每個「字母」,看看它是一個字符,int oder運算符,然後聲明一個匹配變量。 – Lotzki
@usmcs更新了問題,對不起。 – user1883573