Python中使用多个谓词调用ifilter的简洁方法

3

我正在通过脚本流式传输一个非常大的集合,目前在简单调用中使用ifilter来拒绝某些值,例如:

ifilter(lambda x: x in accept_list, read_records(filename))

这是一个谓词,但现在我想要添加另一个谓词,并且将来可能还想添加其他谓词。直接的方法是嵌套一个ifilter调用:

ifilter(lambda x : x not in block_list,
    ifilter(lambda x: x in accept_list, read_records(filename)))

我考虑将谓词作为未绑定函数放入列表中,并将它们用于此。然而,这些重复的ifilter调用似乎很难实现(并且可能不是最佳选择)。也许我可以构建一个单一的函数来调用所有的谓词,但我该如何尽可能简洁地编写它(同时保持可读性)?

3个回答

5
您可以编写以下函数:
def conjoin(*fns):
    def conjoined(x):
        for fn in fns:
            if not fn(x): return False
        return True
    return conjoined

然后你会这样调用它:

ifilter(conjoined(lambda x: x not in block_list, lambda x: x in accept_list),
        read_records(filename))

您可以实现类似的disjoin函数来将函数进行运算:

def disjoin(*fns):
    def disjoined(x):
        for fn in fns:
            if fn(x): return True
        return False
    return disjoined

可能有更好的实现方式,但需要小心。可以尝试将每个函数应用于x并使用allany,但这是不可取的,因为使用它们需要在参数上评估每个谓词。此处提供的解决方案具有令人满意的短路效应。

另外,只是为了好玩,让我们实现一个invert函数。

def invert(fn):
    return lambda x: not fn(x)

现在,我们拥有一个功能完备的函数操作集合,可以使用它们构建任何逻辑操作 :)

1
我会坚持以下解决方案:
def complex_predicate(x):
    return x not in block_list and x in accept_list and is_good(x)

或者

def complex_predicate2(x):
    return all([x not in block_list, x in accept_list, is_good(x)])

然后

ifilter(complex_predicate, read_records(filename))

或者使用 complex_predicate2 也可以。

但是,我认为这只是个人口味问题。


0
如果只有两个谓词,我会想出以下内容:
ifilter(lambda x: x in accept_list and x not in block_list, read_records(filename))

此外,正如上面提到的那样,如果有超过两个谓词,最好将所有谓词放在特定函数中。 使用all可以使条件块变得更加简洁(因为在这种情况下,所有谓词都用逗号分隔)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接