逻辑组合 class 个实例

Logically combine class instances

我有一组过滤器对象,它们继承了 Filter 基础 class

的属性
class Filter():
    def __init__(self):
        self.filterList = []

    def __add__(self,f):
        self.filterList += f.filterList  

    def match(self, entry):
        for f in self.filterList:
            if not f(entry):
               return False
        return True

class thisFilter(Filter):
    def __init__(self, args):
        super().__init__()
        ....
        def thisFilterFunc(entry)->bool:
            return True

        self.filterList.append(thisFilterFunc)

这个过滤器 classes 被各种函数用来过滤条目

def myfunc(myfilter, arg1, ...):
    ...
    for entry in entries:
        if myfilter.match(entry):
            ... do something

可以通过添加这些过滤器的实例来添加多个过滤器(逻辑与):

bigFilter = filter1 + filter2 + ...

这一切都很好地结合在一起,但我很乐意以一种处理更复杂的逻辑约束的方式对此进行概括,例如

bigFilter = (filter1 and filter2) or (filter3 and not filter4)

感觉这应该可以通过覆盖 class 的 __bool__ 而不是使用 __add__ 来实现,但是 class 的布尔值只知道一个给定的条目,而不是在过滤器的组装过程中。

任何想法如何使这成为可能?或者是否有更 pythonic 的方法来做到这一点?

我会选择这样的东西:

class Filter:
  def __init__(self, filter: Callable[[Any], bool]):
    self.filter = filter

  def __add__(self, added: Filter):
    return OrFilter(self, added)

  def __mul__(self, mult: Filter):
    return AndFilter(self, mult)

  def __invert__(self):
    return Filter(lambda x: not self.filter(x))

  def __call__(self, entry):
    return self.filter(entry)

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

  def __call__(self, entry):
    return self.left(entry) and self.right(entry)

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

  def __call__(self, entry):
    return self.left(entry) or self.right(entry)

然后您可以创建过滤器,并将它们用作 (filterA + ~filterB) * filterC

您可能希望将 Any 替换为通用类型,以便您的过滤器知道它在处理什么。

谢谢@njzk2 的解决方案。在我的代码中,我使用了 |&。为了向后兼容,我还保留了 .match() 而不是使用 __call__() 并再次添加了 __add__

class Filter:
    def __init__(self, filter: Callable[[Any], bool]):
        self.filter = filter

    def __or__(self, ored: Filter):
        return OrFilter(self, ored)

    def __and__(self, anded: Filter):
        return AndFilter(self, anded)
    
    def __add__(self, added: Filter):
        # self as __and__
        return self.__and__(added)

    def __invert__(self):
        return Filter(lambda x: not self.filter(x))

    def match(self, entry):
        return self.filter(entry)

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

  def filter(self, entry):
    return self.left.filter(entry) and self.right.filter(entry)

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

  def filter(self, entry):
    return self.left.filter(entry) or self.right.filter(entry)

class MyFilter(Filter):
    def __init__(self, args):
        ...
        def ffunc(entry) -> bool:
            ...
        super().__init__(ffunc)