У меня есть некоторые предикаты, например:
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
, а и
и или
являются операторами замыкания. Ближайшее, что я придумал, - это определить класс P
, который представляет собой простой контейнер предикатов, который реализует __ call __ ()
и имеет методы и _ ()
и или _ ()
для объединения предикатов. Определение из 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)
, который эквивалентен приведенной выше лямбда-функции . Это ближе к тому, что я бы сказал ke, но он также не является бессмысленным (теперь точки являются самими предикатами, а не их аргументами).Теперь второй вопрос: есть ли лучший или более короткий способ (может быть, без скобок и точек) для объединения предикатов в Python, чем использование классов вроде P
и без использования (лямбда) функций?