8

「ロジック パズル」を解くための簡単なスクリプトを書きました。これは、多くの規則が与えられ、「A、B、C という名前の 5 人のミュージシャンがいます。 、D、および E がコンサートで演奏している場合、それぞれが次々に演奏します... A が B の前にあり、D が最後ではない場合...誰がいつ演奏するかの順序は何ですか?」等

可能な解決策を評価するために、各「ルール」を個別の関数として記述しました。この関数は、可能な解決策 (単純に文字列のリストとして表される) が有効かどうかを評価します。たとえば、

#Fifth slot must be B or D
def rule1(solution):
    return solution[4] == 'B' or solution[4] == 'D'

#There must be at least two spots between A and B
def rule2(solution):
    returns abs(solution.index('A') - solution.index('B')) >= 2

#etc...

最初のルールが失敗した後にルールの評価を停止する機能を備えた、可能な解決策がそのようなすべてのルールに合格するかどうかをテストする Pythonic の方法を見つけることに興味があります。

最初に、可能な限り単純なことを書きました。

def is_valid(solution):
    return rule1(solution) and rule2(solution) and rule3(solution) and ...

しかし、これはかなり醜いようでした。リスト内包表記のようなものを使用して、これをもう少しエレガントに読むことができるのではないかと思いました...

def is_valid(solution)
    rules = [rule1, rule2, rule3, rule4, ... ]
    return all([r(solution) for f in rules])

all()...しかし、関数が評価される前にリスト内包表記が生成されるため、これにはまったく短絡しないという副作用があることに気付きました-最初のルールが返された場合でも、すべてのルールが評価されますFalse.

だから私の質問は:の長いリストを書き出す必要なしに、ショートサーキットを使用してTrue/式のリストを評価できる、よりPythonic/機能的な方法はありますか?Falsereturn f1(s) and f2(s) and f3(s) ...

4

1 に答える 1

13

ジェネレータ式を使用します:

rules = [ rule1, rule2, rule3, rule4, ... ]
rules_generator = ( r( solution ) for r in rules )
return all( rules_generator )

シンタックス シュガー: 余分な括弧は省略できます。

rules = [ rule1, rule2, rule3, rule4, ... ]
return all( r( solution ) for r in rules )

ジェネレーターは (基本的に).next()メソッドを持つオブジェクトであり、反復可能なオブジェクトの次のアイテムを返します。これは、ファイルをすべてメモリにロードせずにチャンクで読み取る、または巨大な整数まで反復するなどの便利なことを実行できることを意味します。for透過的にループを使用してそれらを反復できます。Python はそれを裏で処理します。たとえばrange、Py3k のジェネレータです。

関数定義のyield代わりにステートメントを使用して、独自のカスタム ジェネレーター式を展開できます。return

def integers():
    i = 0
    while True:
        yield i

Python は、関数の状態などの保存を処理します。彼らは素晴らしいです!

于 2010-08-04T13:11:57.537 に答える