2つのオブジェクトは、等しい[1]を比較しない限り、同じ値にハッシュすることは保証されません。
Python関数(lambdaを含む)は、同じコード[2]を持っていても等しいとは限りません。例:
>>> (lambda: 1) == (lambda: 1)
False
実装上、この動作は、関数オブジェクトが独自の等価演算子を提供しないためです。代わりに、オブジェクトのアイデンティティ、すなわちそのアドレスを使用するデフォルトのものを継承します。 documentationから:NO __cmp__()
、__eq__()
又は__ne__()
操作が定義されていない場合
、クラス インスタンスは、オブジェクトアイデンティティ(「アドレス」)によって比較されます。
ここでは、あなたの特定の例では何が起こるかです:アドレスA
は常に一つの値、および別のアドレスB
にハッシュされているので
fn = lambda: 1 # New function is allocated at address A and stored in fn.
fn = lambda: 1 # New function is allocated at address B and stored in fn.
# The function at address A is garbage collected.
fn = lambda: 1 # New function is allocated at address A and stored in fn.
# The function at address B is garbage collected.
fn = lambda: 1 # New function is allocated at address B and stored in fn.
# The function at address A is garbage collected.
...
、次の2つの値の間hash(fn)
交互に見ています。しかし、この交互の動作は実装のアーチファクトであり、たとえばガベージコレクタがわずかに異なるように動作するようにすると、ある日に変更される可能性があります。
次洞察に満ちたノートは@ruakhによって寄与されました:
それはそれは2つの機能が等価であるかどうかを決定するための一般的なプロセス を書くことは可能ではないことは注目に値します。 (これは、halting problemのundecidabilityの 結果である。)(これらは 異なる、しかし、同じ名前の変数を参照するクロージャであってもよいので) さらに、2つのPythonの機能は、それら コードが同一であっても異なって振る舞うことができます。したがって、 Python関数は等価演算子をオーバーロードしません。 は、デフォルトのオブジェクトIDよりも優れたものを実装する方法はありません 比較。
[1]逆は同じではない2つのオブジェクトは、同じハッシュ値を持つことができます。これはhash collisionと呼ばれます。
>>> (lambda: 1)() == (lambda: 1)()
True
出典
2015-11-30 12:34:23
NPE
実際の関数オブジェクト自体をハッシュしていることに気付くだけで、呼び出されたときに返される値をハッシュ化しているわけではありません。 –
これはおそらく悪い考えですが、コードオブジェクト 'hash((lambda:1).__ code __) ' – berdario
だけを考えればいいのでしょうか...この機能が必要なモデルは何ですか?あなたは一般的に任意の関数に基づいて辞書の中のものを調べますか? –