0

我正在使用 PuLP 开发一个项目,我正在尝试创建一个终端提示符以允许用户输入他们的数据,然后我的 Python 程序会将输入更改为 PuLP 可读的代码。为此,我必须允许用户输入:

2*a + 3*b <= c

我的代码将 eval() 这段代码以及创建变量 a、b 和 c 等

a = LpVariable("a",None,None,LpContinuous)
b = LpVariable("b",None,None,LpContinuous)
c = LpVariable("c",None,None,LpContinuous)

有任何想法吗?我试过使用 exec() 但它似乎不太喜欢。

目前我通过以下方式获得输入:

print "Please enter your constraints 1 at a time and enter '#' when done:"
control = True
while (control):
    entry = raw_input('-->')
    entryS = ""
    entryS += entry

所以字符串 2*a+3*B <= c 存储为 entryS

4

2 回答 2

1

使用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_*方法即可。

数字都是ints,你可能不想要。您可能应该添加floats 和/或将所有数字转换为decimal.Decimal.

我可能会编写一个真正的解析器,而不是eval()使用 pyparsing,或者,我最喜欢这样的东西,Parcon。

于 2014-11-17T01:40:17.177 回答
0

entryS = "" 

在while循环之前。

于 2012-12-06T20:43:20.817 回答