我正在尝试从表达式树创建收集过滤器(这些过滤器将使用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方式解决此问题的建议或指示,将不胜感激!
最佳答案
我假设您的表达式树由许多对象组成,它们的类型与它的表达式类型相对应。例如或者,等于,字符串等。类似这样的东西:
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