1

次のコードがあります。

def evAnd(v, *predicates):
    satisfied=True
    for f in predicates:
        if not f(v):
            satisfied=False
            # log: f,v->False in a map and other side effects
        else:
            # log: f,v->True in a map and other side effects
    return satisfied


def evOr(v, *predicates):
    satisfied=False
    for f in predicates:
        if f(v):
            satisfied=True
            # log: f,v->True in a map and other side effects
        else:
            # log: f,v->False in a map and other side effects
    return satisfied

上記を単一の関数に統合する Pythonic の方法は何ですか? (ログメッセージが配置される場所にはかなりの副作用コードあるため)

受け入れられた回答に基づく解決策

したがって、受け入れられた回答に基づいて、最終的に私が行ったことは次のとおりです。

def adorn(predicate):
    def rv(v):
        rvi = predicate(v)
        if rvi:
            print "%s is satisfied for value %d" % (predicate.__name__, v)
            # any other side effects
        else:
            print "%s is not satisfied for value %d" % (predicate.__name__, v)
            # any other side effects
        return rvi
    return rv


def my_all(n, predicates):
    return reduce(operator.and_, map( lambda x : x(n), map(adorn, predicates)), True)

def my_any(n, predicates):
    return reduce(operator.or_, map( lambda x : x(n) , map(adorn, predicates)), False)

次の方法でテストできます。

def even(n):
    return n%2==0

def odd(n):
    return n%2!=0

print my_all(3, [even, odd])
print my_any(4, [even, odd])
4

3 に答える 3

5

一般的に言えば、ジェネレータ式をanyまたはallに渡すとショートサーキットになりますが、LC にしてこれらの両方のビルトインに渡すと、ショートサーキットは不可能になり、必要な効果が得られます。追及する

次のデモンストレーションは自明であり、問​​題に適応させることができます

>>> count = 0
>>> def foo(n):
    global count
    count += 1
    return n%2

>>> any(foo(n) for n in range(10))
True
>>> count
2
>>> count = 0
>>> any([foo(n) for n in range(10)])
True
>>> count
10

Blender で提案されているように、破棄すべきリストが作成される可能性があります。よりジェネレーター指向のソリューションは次のようになります

anyこの問題を調べるもう 1 つの方法 (少なくともジェネレーターの場合) は、 orによって短絡されている場合、残りの iterable を消費することですall消費する itertools レシピを部分的に借りることで、簡単に行うことができます

>>> count
0
>>> it = (foo(n) for n in range(10))
>>> any(it)
True
>>> collections.deque(it, maxlen = 0)
deque([], maxlen=0)
>>> count
10

そして、ここにショートしない2つのバージョンがあります。これらの関数に意味のある名前を付けてください (私は本当に苦手です)。

>>> def all_noss(expr):
    it = iter(expr)
    result = any(it)
    collections.deque(it, maxlen = 0)
    return result

>>> def any_noss(expr):
    it = iter(expr)
    result = any(it)
    collections.deque(it, maxlen = 0)
    return result
于 2013-02-01T08:26:34.583 に答える
2

単純にどうですか

reduce(operator.and_, seq)

「すべて」の場合、および

reduce(operator.or_, seq)

「任意」の場合。

于 2013-02-01T09:08:48.833 に答える
1

あなたは利用することができますreduce

def evAnd(v, *predicates):
    return reduce(lambda x, y: x and y, [f(v) for f in predicates])

def evOr(v, *predicates):
    return reduce(lambda x, y: x or y, [f(v) for f in predicates])

allまたはを利用するany

def evAnd(v, *predicates):
    return all([f(v) for f in predicates])

def evOr(v, *predicates):
    return any([f(v) for f in predicates])

上記のメソッドはリスト内包表記を作成するため、すべての述語は短絡することなく評価されます。

更新

リスト内包表記の欠点は、メモリ内にリストを作成することです。それが懸念事項である場合は、代わりにジェネレーターを使用できます。

def evAnd(v, *predicates):
    return reduce(lambda x, y: x and y, (f(v) for f in predicates))

def evOr(v, *predicates):
    return reduce(lambda x, y: x or y, (f(v) for f in predicates))

今回は、を使用する必要がありますがreduceallまたはany短絡が発生する可能性がありますが、これは望ましくありません。

@NPEによって思い出されるように、ラムダを演算子に置き換えることができます。

def evAnd(v, *predicates):
    return reduce(operator.and_,  (f(v) for f in predicates))

def evOr(v, *predicates):
    return reduce(operator.or_,  (f(v) for f in predicates))
于 2013-02-01T08:28:00.013 に答える