结合列表中的几个逻辑条件

时间:2014-08-08 20:20:19

标签: python list expression exec logical-operators

我试图做一些看似简单的事情:我有一个列表,其元素是逻辑表达式,我想要一个函数将它们组合成一个逻辑表达式,使用选择的逻辑运算符(&或|是足够)。

以下代码执行此操作,但是,不应该有更好的方法吗?它对我来说并不觉得非常诡异(我看到的主要问题是使用" exec",有没有人知道怎么做?):

def CombineLogicalExpressions(listofexpressions,operator,outputvariableName):
    ''' return a condition combined from individual ones
    listofexpressions = ["a == 1", "b == 2"]
    operator = "and"
    outputvariableName = 'myVar'
    '''
    #generate list from which the condition can be read:
    logicalconditions = []
    for expression in listofexpressions:
        logicalconditions.append(expression)
        logicalconditions.append(' ' + str(operator) + ' ')
    del logicalconditions[-1] # delete the final operator

    #create string that holds the full expression
    condition = ''
    for a in logicalconditions:
        condition = condition + a   
    condition = 'FinalExpression = (' + condition + ')'

    return condition

FinalExpression = False
a = 1
b = 2

condition = CombineLogicalExpressions(['a == 1', 'b == 2'] ,
                                           'and', 'FinalExpression')
#set FinalBooleanQueryResult to the outcome of executing condition:
exec condition
print FinalExpression

您可能想知道为什么我会将逻辑条件作为字符串。这是上面代码的简化。实际上,我有一个容器对象' someContainer'它有一个方法' .contains(string)'它将返回一个查询,该查询可用于对容器进行切片并为其键包含' string':

的所有条目
 #returns sliced someContainer with keys matching 'string'
 someContainer[someContainer.contains(string)]

现在我想扩展' contains()'的功能。能够提供字符串列表:

#returns sliced someContainer with keys matching all strings in 'listofkeywords'
containsMultiple(someContainer, listofkeywords)

我希望这不会太长,也不会特别让人们离开!我试着寻找答案,但令我惊讶的是找不到任何东西。

2 个答案:

答案 0 :(得分:2)

您可以轻松地使用any()all()内置词:

class Container(object):
    def __init__(self, items):
        self.items = items

    def contains(self, s):
        return s in self.items


def contains_any(some_container, items):
    return any((some_container.contains(i) for i in items))


def contains_all(some_container, items):
    return all((some_container.contains(i) for i in items))


c = Container(['foo', 'bar'])

print contains_any(c, ['foo', 'qux'])
print contains_all(c, ['foo', 'qux'])
print contains_all(c, ['foo', 'bar'])

输出:

True
False
True

(some_container.contains(i) for i in items)any()来电中的all()是所谓的generator expression。它类似于列表理解,但它很懒,可能会节省你对Container.contains()的大量调用。

答案 1 :(得分:1)

事实上,我使用“reduce”功能和操作员模块为我的问题找到了一个非常好的和简洁的解决方案。运算符模块将二元运算符转换为带有两个参数的函数,如:

 operator.and_(A,B) equivalent to: (A and B).

Reduce将累积两个参数的函数应用于参数列表,即

reduce(function,[A,B,C]) equivalent to: function( A, function(B,C) )

有了这个,我将给出解决我在下面给出的原始简化问题的代码。请注意,这尤其适用于我实际感兴趣的容器:

def CombineLogicalExpressionsBetter(listofexpressions,operatorname):
    '''
    use as:
    CombineLogicalExpressionsBetter([a == 1, b == 2, c == 'z'], 'and')
    '''
    import operator

    #make it easier for users to enter operators:
    if operatorname in ('and','and_') :
        operatorname = operator.and_
    elif operatorname in ('or','or_'):
        operatorname = operator.or_
    elif operatorname in ('not','not_'):
        operatorname = operator.not_
    else:
        raise Exception("Please enter a valid operator: 
                    'and', 'or', 'not' ... I got: " + operatorname)


    #combine expression:
    totalexpression = reduce(operatorname, (expression for expression in
                                                       listofexpressions))

    return totalexpression