У меня есть некоторые предикаты, например:
is_divisible_by_13 = lambda i: i % 13 == 0
is_palindrome = lambda x: str(x) == str(x)[::-1]
и хотите логически объединить их, как в:
filter(lambda x: is_divisible_by_13(x) and is_palindrome(x), range(1000,10000))
Теперь возникает вопрос: может ли такая комбинация быть написана в стиле без точек, например:
filter(is_divisible_by_13 and is_palindrome, range(1000,10000))
Это, конечно, не имеет желаемого эффекта, поскольку истинное значение лямбда-функций равно True
, а and
и or
являются операторами короткого замыкания. Самое близкое, что я придумал, это определить класс P
, который представляет собой простой контейнер предикатов, который реализует __call__()
и имеет методы and_()
и or_()
для объединения предикатов. Определение P
выглядит следующим образом:
import copy
class P(object):
def __init__(self, predicate):
self.pred = predicate
def __call__(self, obj):
return self.pred(obj)
def __copy_pred(self):
return copy.copy(self.pred)
def and_(self, predicate):
pred = self.__copy_pred()
self.pred = lambda x: pred(x) and predicate(x)
return self
def or_(self, predicate):
pred = self.__copy_pred()
self.pred = lambda x: pred(x) or predicate(x)
return self
Теперь с помощью P
я могу создать новый предикат, представляющий собой комбинацию таких предикатов:
P(is_divisible_by_13).and_(is_palindrome)
что эквивалентно приведенной выше лямбда-функции. Это ближе к тому, что я хотел бы иметь, но также не является бесточечным (точки теперь являются самими предикатами, а не их аргументами). Теперь второй вопрос: есть ли лучший или более короткий способ (возможно, без круглых скобок и точек) для объединения предикатов в Python, чем использование классов, таких как P
, и без использования (лямбда) функций?