python
クラスのset()
および___hash__
_メソッドを使用して、同じハッシュオブジェクトがセットに追加されないようにしています。 python data-model document によると、set()
は同じハッシュオブジェクトを同じオブジェクトと見なし、一度追加するだけです。
ただし、以下のように動作が異なります。
_class MyClass(object):
def __hash__(self):
return 0
result = set()
result.add(MyClass())
result.add(MyClass())
print(len(result)) # len = 2
_
文字列値の場合、それは正しく動作します。
_result.add('aida')
result.add('aida')
print(len(result)) # len = 1
_
私の質問は、同じハッシュオブジェクトがセット内で同じでないのはなぜですか?
あなたの読みは正しくありません。 __eq__
メソッドは等価チェックに使用されます。ドキュメントには、__hash__
の値がa == b
(つまりa.__eq__(b)
)がtrueである2つのオブジェクトa
およびb
でも同じである必要があると記載されています。
これはよくあるロジックの間違いです。a == b
がtrueである暗黙hash(a) == hash(b)
もtrueであること。ただし、含意は必ずしもequivalenceを意味するわけではなく、以前のhash(a) == hash(b)
に加えて、 a == b
。
MyClass
のすべてのインスタンスを互いに同等にするには、それらに__eq__
メソッドを提供する必要があります。そうでない場合Pythonは代わりにアイデンティティを比較しますこれは次のようになります:
class MyClass(object):
def __hash__(self):
return 0
def __eq__(self, other):
# another object is equal to self, iff
# it is an instance of MyClass
return isinstance(other, MyClass)
今:
>>> result = set()
>>> result.add(MyClass())
>>> result.add(MyClass())
1
実際には、__hash__
の比較に使用されるオブジェクトのプロパティに基づいて__eq__
を作成します。次に例を示します。
class Person
def __init__(self, name, ssn):
self.name = name
self.ssn = ssn
def __eq__(self, other):
return isinstance(other, Person) and self.ssn == other.ssn
def __hash__(self):
# use the hashcode of self.ssn since that is used
# for equality checks as well
return hash(self.ssn)
p = Person('Foo Bar', 123456789)
q = Person('Fake Name', 123456789)
print(len({p, q}) # 1
セットはオブジェクトをハッシュ可能にするためにtwoメソッドを必要とします:__hash__
および__eq__
。 2つのインスタンスmustは、等しいと見なされたときに同じハッシュ値を返します。両方のハッシュがセットに存在する場合、インスタンスはすでにセットに存在すると見なされますandインスタンスは、セット内に同じハッシュを持つインスタンスの1つと等しいと見なされます。
クラスは__eq__
を実装していないため、代わりにデフォルトのobject.__eq__
が使用され、obj1 is obj2
もtrueの場合にのみtrueを返します。言い換えると、2つのインスタンスが等しいと見なされるのは、それらがまったく同じインスタンスの場合のみです。
それらのハッシュが一致するからといって、セットに関する限り、それらが一意になるわけではありません。テーブルサイズに対するハッシュのmodulusが使用されるため、異なるハッシュを持つオブジェクトでも同じハッシュテーブルスロットに入れられる可能性があります。
2つのインスタンスが等しいと想定される場合にTrue
を返すカスタム__eq__
メソッドを追加します。
def __eq__(self, other):
if not isinstance(other, type(self)):
return False
# all instances of this class are considered equal to one another
return True