class A(object):
x = 4
i = A()
d = {}
d[i] = 2
print d
i.x = 10
print d
は、私が唯一不変オブジェクトは辞書のキー可能と思ったが、オブジェクトの上に、私は変更可能です。私はpythonで辞書キーとして可変オブジェクトを使用することができます。これは許されないのですか?
class A(object):
x = 4
i = A()
d = {}
d[i] = 2
print d
i.x = 10
print d
は、私が唯一不変オブジェクトは辞書のキー可能と思ったが、オブジェクトの上に、私は変更可能です。私はpythonで辞書キーとして可変オブジェクトを使用することができます。これは許されないのですか?
__hash__メソッドを持つ任意のオブジェクトは、辞書のキーすることができます。あなたが書くクラスの場合、値を返すには、このメソッドのデフォルトはID(自己)をオフに基づいて、と平等はそれらのクラスのIDによって決定されていない場合、あなたがキーとしてそれらを使用することによって驚かれることがあります。
>>> class A(object):
... def __eq__(self, other):
... return True
...
>>> one, two = A(), A()
>>> d = {one: "one"}
>>> one == two
True
>>> d[one]
'one'
>>> d[two]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: <__main__.A object at 0xb718836c>
>>> hash(set()) # sets cannot be dict keys
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
バージョン2.6で変更:__hash__をNoneに設定すると、クラスのインスタンスに明示的にフラグを立てることができます。 [__hash__]
class Unhashable(object):
__hash__ = None
要件は、オブジェクトのハッシュが経時的に変化しないことであり、それは元の値と等しい(==)を比較し続けること。クラスAはこれらの要件を両方満たすため、有効な辞書キーを作成します。 x属性はキーイングではまったく考慮されません。それはhashableある場合
オブジェクトは、辞書内の鍵となるKAN。ここ
は、文書からハッシュ可能の定義である:
オブジェクトは、その寿命の間に変化しないハッシュ値を持つ場合(それは
__hash__()
方法を必要とする)ハッシュ可能であり、他と比較することができますオブジェクト(__eq__()
または__cmp__()
メソッドが必要です)。等しいを比較するハッシュ可能オブジェクトは、同じハッシュ値を持たなければなりません。Hashabilityは、これらのデータ構造が内部的にハッシュ値を使用するため、オブジェクトを辞書キーとセットメンバーとして使用できます。
変更可能なコンテナ(リストや辞書など)はありませんが、Pythonの変更不可能なビルトインオブジェクトはすべてハッシュ可能です。ユーザ定義のクラスのインスタンスであるオブジェクトは、デフォルトでハッシュ可能です。それらはすべて不等価であり、ハッシュ値はid()です。
object
は__hash__
、__eq__
と__cmp__
のデフォルトの実装を提供するので、これは、明示的にハッシュ可能ではないと定義されていない限りobject
から派生するものはハッシュ可能であることを意味します。ハッシュ可能な変更可能な型を作成することはできませんが、必要に応じて動作しない可能性があります。フレッド・nurkの例@
は、上記幸運にも、もはやためthis changeの、Pythonの3で動作しません:
__eq__()
をオーバーライドし、その__hash__()
が暗黙的にNone
に設定されます__hash__()
を定義していないクラス。クラスの__hash__()
方法がNone
ある場合は、プログラムがそのハッシュ値を取得しようとしたとき、クラスのインスタンスは、適切なTypeError
を発生させます...
は、そのために神に感謝します。しかし、あなた自身で__hash__()
を明示的に定義しても、悪いことを行うことはできます。
class BadHasher:
def __init__(self):
self.first = True
# Implement __hash__ in an evil way. The first time an instance is hashed,
# return 1. Every time after that, return 0.
def __hash__(self):
if self.first:
self.first = False
return 1
return 0
myobject = BadHasher()
# We can put this object in a set...
myset = {myobject}
# ...but as soon as we look for it, it's gone!
if myobject not in myset:
print("what the hell we JUST put it in there")