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

wds*_*wds 3 python iterator functional-programming

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

ifilter(lambda x: x in accept_list, read_records(filename))
Run Code Online (Sandbox Code Playgroud)

这是一个谓词,但现在我发现我应该添加另一个,我可能希望将来添加其他谓词.直截了当的方式是嵌套一个ifilter电话:

ifilter(lambda x : x not in block_list,
    ifilter(lambda x: x in accept_list, read_records(filename)))
Run Code Online (Sandbox Code Playgroud)

我想简单地将谓词作为未绑定的函数放在列表中并使用它们.虽然这些重复的ifilter调用似乎很难实现(并且可能不是最佳选择).也许我可以构造一个调用所有谓词的函数,但是如何尽可能简洁地(虽然仍然可读)编写它?

Ant*_*sky 5

您可以编写以下函数:

def conjoin(*fns):
    def conjoined(x):
        for fn in fns:
            if not fn(x): return False
        return True
    return conjoined
Run Code Online (Sandbox Code Playgroud)

然后你会这样称呼它:

ifilter(conjoined(lambda x: x not in block_list, lambda x: x in accept_list),
        read_records(filename))
Run Code Online (Sandbox Code Playgroud)

你可以一起disjoinor -ing函数实现一个类似的函数:

def disjoin(*fns):
    def disjoined(x):
        for fn in fns:
            if fn(x): return True
        return False
    return disjoined
Run Code Online (Sandbox Code Playgroud)

可能有更好的方法来实现它们,但必须要小心.有人可能会尝试将每个函数应用于x和使用allany,但这是不可取的,因为使用它们将需要评估参数的每个谓词.这里提出的解决方案是令人满意的短路.

另外,为了好玩,让我们实现一个invert功能

def invert(fn):
    return lambda x: not fn(x)
Run Code Online (Sandbox Code Playgroud)

现在,我们有一套功能完备的函数操作函数,并且可以构造这些函数中的任何逻辑运算:)