2

我正在尝试从表达式树创建集合过滤器(这些过滤器将使用 wxpython 树控件从 GUI 生成)。然后我会将这些过滤器与 python 的 filter(func, iterable) 方法一起使用。

现在的挑战是如何根据表达式树中的规则在运行时创建函数。这种函数的外观示例如下:

def filterFunc(element):
    if element == 'Apple' or element == 'Orange' or element == 'Duck':
        return True
    return False

我目前正在考虑的解决方案是遍历树,根据树的内容生成一个包含实际 Python 代码的字符串(可能对代码很痛苦),然后在生成的字符串上调用 eval()。

任何有关解决此问题的正确/pythonic方法的建议或指示将不胜感激!

4

1 回答 1

3

我假设您的表达式树由许多对象组成,其类型对应于它的表达式类型。前任。或者,等于、字符串等。像这样的东西:

class OrExpression:
    def __init__(self, left, right):
        self.left = left
        self.right = right

class EqualsExpression:
    def __init__(self, left, right):
        self.left = left
        self.right = right

class Literal:
    def __init__(self, value):
        self.value = value

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

与您的示例等效的表达式如下所示:

e = OrExpression(
    EqualsExpression(
        Variable("element"),
        Literal("Apple")
    ),
    OrExpression(
        EqualsExpression(
            Variable("element"),
            Literal("Orange")
        ),
        EqualsExpression(
            Variable("element"),
            Literal("Duck")
        )
    )
)

您可以为每个类创建一个eval针对给定上下文评估自身的方法。像这样:

class OrExpression:
    def __init__(self, left, right):
        self.left = left
        self.right = right
    def eval(self, variables):
        return self.left.eval(variables) or self.right.eval(variables)

class EqualsExpression:
    def __init__(self, left, right):
        self.left = left
        self.right = right
    def eval(self, variables):
        return self.left.eval(variables) == self.right.eval(variables)

class Literal:
    def __init__(self, value):
        self.value = value
    def eval(self, variables):
        return self.value

class Variable:
    def __init__(self, name):
        self.name = name
    def eval(self, variables):
        return variables[self.name]

然后您可以调用eval并提供上下文。在您的示例中,您只需要传入element.

print e.eval({"element": "Apple"})
print e.eval({"element": "Duck"})
print e.eval({"element": "Banana"})

结果:

True
True
False

但是,如果您不按类型区分表达类型怎么办?假设您的树由普通的旧节点组成,这些节点标识它们使用其value属性的表达式类型。代码大致相同,只是使用单个单片开关盒,而不是单独的eval方法。

class Node:
    def __init__(self, value=None, *children):
        self.value = value
        self.children = children

def evalTree(t, variables):
    if t.value == "Or":
        return evalTree(t.children[0], variables) or evalTree(t.children[1], variables)
    elif t.value == "Equals":
        return evalTree(t.children[0], variables) == evalTree(t.children[1], variables)
    elif t.value == "Literal":
        return t.children[0].value
    elif t.value == "Variable":
        name = t.children[0].value
    else:
        raise Exception("Unrecognized node type")

t = Node("Or",
    Node("Equals",
        Node("Variable", Node("element")),
        Node("Literal", Node("Apple"))
    ),
    Node("Or",
        Node("Equals",
            Node("Variable", Node("element")),
            Node("Literal", Node("Apple"))
        ),
        Node("Equals",
            Node("Variable", Node("element")),
            Node("Literal", Node("Apple"))
        )
    )
)

print evalTree(t,{"element": "Apple"})
print evalTree(t,{"element": "Duck"})
print evalTree(t,{"element": "Banana"})

结果:

True
True
False
于 2013-10-02T15:30:42.333 回答