9

私はいくつかの述語を持っています、例えば:

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))

もちろん、ラムダ関数の真偽値はTrueandandor短絡演算子であるため、これは望ましい効果をもたらしません。私が思いついた最も近いものは、メソッドを実装して持つ単純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)

これは上記のラムダ関数と同等です。これは私が望んでいるものに近づきますが、無意味でもありません (ポイントは、引数ではなく述語そのものになりました)。2番目の質問は次のとおりですP。(ラムダ)関数を使用せずにクラスのようなクラスを使用するよりも、Pythonで述語を結合するためのより良いまたはより短い方法(おそらく括弧とドットなし)はありますか?

4

5 に答える 5

3

基本的に、あなたのアプローチはPythonで実行可能な唯一のアプローチのようです。githubには、ポイントフリーの関数合成を実装するためにほぼ同じメカニズムを使用するPythonモジュールがあります。

私はそれを使用していませんが、一見すると彼のソリューションは少し良く見えます(クラスとを使用する場所でデコレータと演算子のオーバーロードを使用しているため__call__)。

しかし、それ以外は、技術的にはポイントフリーのコードではありませんが、必要に応じて「ポイント非表示」になっています。どちらがあなたにとって十分かもしれないし、そうでないかもしれません。

于 2012-02-07T22:18:00.610 に答える
2

Infix演算子のレシピを使用できます:

AND = Infix(lambda f, g: (lambda x: f(x) and g(x)))
for n in filter(is_divisible_by_13 |AND| is_palindrome, range(1000,10000)):
    print(n)

収量

1001
2002
3003
4004
5005
6006
7007
8008
9009
于 2012-02-07T22:33:38.707 に答える
2

Python には、ラムダという 2 つの関数を組み合わせる方法が既にあります。独自の構成機能と複数の構成機能を簡単に作成できます。

compose2 = lambda f,g: lambda x: f(g(x))
compose = lambda *ff: reduce(ff,compose2)

filter(compose(is_divisible_by_13, is_palindrome, xrange(1000)))
于 2013-07-20T16:55:41.867 に答える
1

それが私の解決策です:

class Chainable(object):

    def __init__(self, function):
        self.function = function

    def __call__(self, *args, **kwargs):
        return self.function(*args, **kwargs)

    def __and__(self, other):
        return Chainable( lambda *args, **kwargs:
                                 self.function(*args, **kwargs)
                                 and other(*args, **kwargs) )

    def __or__(self, other):
        return Chainable( lambda *args, **kwargs:
                                 self.function(*args, **kwargs)
                                 or other(*args, **kwargs) )

def is_divisible_by_13(x):
    return x % 13 == 0

def is_palindrome(x):
    return str(x) == str(x)[::-1]

filtered = filter( Chainable(is_divisible_by_13) & is_palindrome,
                   range(0, 100000) )

i = 0
for e in filtered:
    print str(e).rjust(7),
    if i % 10 == 9:
        print
    i += 1

そして、これが私の結果です:

    0     494     585     676     767     858     949    1001    2002    3003
 4004    5005    6006    7007    8008    9009   10101   11011   15951   16861
17771   18681   19591   20202   21112   22022   26962   27872   28782   29692
30303   31213   32123   33033   37973   38883   39793   40404   41314   42224
43134   44044   48984   49894   50505   51415   52325   53235   54145   55055
59995   60606   61516   62426   63336   64246   65156   66066   70707   71617
72527   73437   74347   75257   76167   77077   80808   81718   82628   83538
84448   85358   86268   87178   88088   90909   91819   92729   93639   94549
95459   96369   97279   98189   99099
于 2012-02-08T13:23:52.560 に答える