tests
のこれらの関数のそれぞれが変数i
を参照しているという問題があります。
より一般的には、これは関数内で行います。この場合、These Nasty Closuresで説明されているように、クロージャーに格納される定義可能範囲の変数i
があります。
しかし、ここではさらに簡単です。i
はグローバル変数であるため、クロージャはありません。この関数は実行時にグローバル変数としてi
を検索するようにコンパイルされます。 i
が変更されたため、関数は実行時に変更された値を表示します。そのような単純な。
(閉鎖やグローバルの両方で動作します)これを回避する伝統的な方法は、愛情を込めて、それは本当にハックではないにもかかわらず、「デフォルト値ハック」として知られています。 (the explanation in the FAQを参照してください。)ライアン・海寧の答えは、これを行う方法について説明します
lambda x, i=i: x%i==0
は、これは、関数が作成された時点でのi
の値に等しいデフォルト値で、i
という名前のパラメータを作成します。次に、関数内で、パラメータi
にアクセスすると、その値が取得されます。
あなたがJavaScriptのような言語に使用している場合より身近に見えるかもしれませんが、この周りの別の方法は、関数の作成関数を作成し、その機能 - の引数としてi
の値を渡すことですuser2864740の答えのように、関数を作成:
(lambda i: lambda x: x%i)(i)
これは、追加のパラメータ(誰かが偶然に引数を渡すことができること)で、関数のシグネチャを「汚染」回避が、関数の作成と呼び出しのコストで正当な理由がないために。この周り
第三の方法は、partial
を使用することです。あなたがしようとしているのは、部分的に関数を適用する場合です。lambda
はラッパー関数を定義する代わりに、partial
を使用するときれいにすることができます。
残念なことに、この場合、関数は演算子の中に隠され、それを公開する関数operator.mod
はキーワード引数をとらないため、2番目のオペランドを部分的に分けることはできません。だから、これはこの場合の悪い解決策です。あなたが本当にしたい場合、あなただけのより良い振る舞いラッパーを書くことができるとpartial
こと:この場合
def opmod(a, b):
return a % b
partial(operator.mod, b=i)
、私はあなたが他のソリューションとのほうだと思います。 がの場合は、頭に入れておいてください。
公式ドキュメントよりも詳しい説明については、[これらの厄介な閉鎖](http://code.activestate.com/recipes/502271/)を参照してください。しかし、短いバージョンでは、これらのテスト関数のそれぞれが同じ変数 'i'を囲むように効果的に閉じ込められ、 'i'は値を変更し続けます。 (これはかなり正確ではありません。なぜなら、グローバル変数は実際にクロージャーに格納する必要はありませんが、その効果は同じです)。 – abarnert