2016-07-18 21 views
6

Tôi đang sử dụng phương thức set()__hash__ của lớp python để tránh thêm cùng một đối tượng băm trong tập hợp. Theo python data-model document, set() xem xét cùng một đối tượng băm giống như đối tượng và chỉ cần thêm chúng một lần.Phương thức Python - class __hash__ và đặt

Nhưng nó hoạt động khác nhau như sau:

class MyClass(object): 

    def __hash__(self): 
     return 0 

result = set() 
result.add(MyClass()) 
result.add(MyClass()) 

print(len(result)) # len = 2 

Trong khi trong trường hợp giá trị chuỗi, nó hoạt động một cách chính xác.

result.add('aida') 
result.add('aida') 

print(len(result)) # len = 1 

Câu hỏi của tôi là: tại sao các đối tượng băm giống nhau không giống nhau?

Trả lời

10

đọc của bạn không đúng. Phương pháp __eq__ được sử dụng để kiểm tra bình đẳng. Các tài liệu chỉ rõ rằng giá trị __hash__ cũng phải giống nhau cho 2 đối tượng aba == b (tức là a.__eq__(b)) là đúng.

Đây là lỗi logic phổ biến: a == b là True ngụ ý rằng hash(a) == hash(b) cũng là True. Tuy nhiên, hàm ý không nhất thiết có nghĩa là tương đương, rằng hash(a) == hash(b) có nghĩa là a == b.

Để thực hiện tất cả các trường hợp MyClass so sánh với nhau, bạn cần cung cấp phương thức __eq__ cho chúng; nếu không thì Python sẽ so sánh các số nhận dạng của chúng thay vì.Điều này có thể làm:

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) 

Bây giờ là:

>>> result = set() 
>>> result.add(MyClass()) 
>>> result.add(MyClass()) 
1 

Trên thực tế bạn muốn dựa vào đó __hash__ trên những thuộc tính của đối tượng của bạn được sử dụng cho __eq__ so sánh, ví dụ:

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 
5

Bộ cần hai phương pháp để tạo đối tượng có thể băm: __hash____eq__. Hai trường hợp phải trả về cùng giá trị băm khi chúng được xem là bằng nhau. Một thể hiện được coi là đã có trong một bộ nếu cả băm có mặt trong tập hợp trường hợp được coi là tương đương với một trong các cá thể có cùng băm đó trong tập hợp.

Lớp học của bạn không triển khai __eq__, do đó, mặc định object.__eq__ được sử dụng thay thế, chỉ trả về true nếu obj1 is obj2 cũng đúng. Nói cách khác, hai trường hợp chỉ được coi là bằng nhau nếu chúng là cùng một ví dụ.

Chỉ vì băm của chúng phù hợp, không làm cho chúng trở nên độc đáo như một tập hợp có liên quan; ngay cả các đối tượng với các hash khác nhau có thể kết thúc trong cùng một khe bảng băm, khi mô-đun của giá trị băm so với kích thước bảng được sử dụng.

Thêm bạn một tùy chỉnh __eq__ phương thức trả về True khi hai trường hợp được coi là tương đương:

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 
Các vấn đề liên quan