21

クラスのメソッドを使用してset()、セットに同じハッシュ オブジェクトを追加しないようにしています。python data-model documentによると、同じハッシュオブジェクトを同じオブジェクトと見なし、それらを一度追加するだけです。__hash__pythonset()

ただし、次のように動作が異なります。

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

私の質問は、なぜ同じハッシュオブジェクトがセット内で同じでないのですか?

4

2 に答える 2

32

あなたの読みは間違っています。メソッドは__eq__等価チェックに使用されます。ドキュメントは、__hash__値が2つのオブジェクトに対しても同じでなければならないと述べaているだけで、 (つまり )はtrueです。ba == ba.__eq__(b)

これはよくある論理の誤りです。a == b真であるということは、それもまた真であることを意味hash(a) == hash(b)ます。ただし、含意は必ずしも同等性を意味するわけではなく、事前確率に加えて、それhash(a) == hash(b)を意味しa == bます。

compareのすべてのインスタンスをMyClass互いに等しくするには、__eq__それらのメソッドを提供する必要があります。それ以外の場合、Python は代わりに IDを比較します。これは次のようになります。

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
于 2016-07-18T06:59:14.797 に答える
12

セットは、オブジェクトをハッシュ可能にするには、 と の 2 つのメソッドが必要です。2 つのインスタンスは、等しいと見なされる場合、同じハッシュ値を返す必要があります。ハッシュがセット内に存在し、インスタンスがセット内の同じハッシュを持つインスタンスの 1 つと等しいと見なされる場合、インスタンスはセット内に既に存在すると見なされます。__hash____eq__

クラスは を実装していない__eq__ため、代わりにデフォルトobject.__eq__が使用されます。これは、 も true の場合にのみ true を返しますobj1 is obj2つまり、2 つのインスタンスは、まったく同じインスタンスである場合にのみ等しいと見なされます。

それらのハッシュが一致するからといって、セットに関する限りそれらが一意になるわけではありません。テーブル サイズに対するハッシュのモジュラスが使用されるため、異なるハッシュを持つオブジェクトでさえ、同じハッシュ テーブル スロットに配置される可能性があります。

2 つのインスタンスが等しいと想定される場合に__eq__返すカスタム メソッドを追加します。True

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
于 2016-07-18T06:59:05.060 に答える