John Millikin đề xuất một giải pháp tương tự như sau:
class A(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
def __eq__(self, othr):
return ((self._a, self._b, self._c) ==
(othr._a, othr._b, othr._c))
def __hash__(self):
return hash((self._a, self._b, self._c))
Vấn đề với giải pháp này là hash(A(a, b, c)) == hash((a, b, c))
. Nói cách khác, hàm băm va chạm với phần tử của các thành viên chính của nó. Có lẽ điều này không quan trọng trong thực tế?
Các Python documentation on __hash__
gợi ý kết hợp băm của các tiểu hợp phần sử dụng một cái gì đó giống như XOR, mang đến cho chúng ta điều này:
class B(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
def __eq__(self, othr):
return (isinstance(othr, type(self))
and (self._a, self._b, self._c) ==
(othr._a, othr._b, othr._c))
def __hash__(self):
return (hash(self._a)^hash(self._b)^hash(self._c)^
hash((self._a, self._b, self._c)))
Bonus: mạnh mẽ hơn __eq__
ném trong đó cho biện pháp tốt.
Cập nhật: như Blckknght chỉ ra, thay đổi thứ tự của a, b và c có thể gây ra sự cố. Tôi đã thêm ^ hash((self._a, self._b, self._c))
bổ sung để nắm bắt thứ tự của các giá trị được băm. Có thể xóa ^ hash(...)
cuối cùng này nếu không thể sắp xếp lại các giá trị được kết hợp (ví dụ: nếu chúng có các loại khác nhau và do đó giá trị của _a
sẽ không bao giờ được gán cho _b
hoặc _c
, v.v ...).
Hm, tôi không nghĩ về điều đó. Tuy nhiên, điều này có thể dẫn đến các bộ/khóa lớn khi số thuộc tính làm cho đối tượng của tôi duy nhất cao. – user229898
Có; nếu đối tượng của bạn là rất lớn, sau đó khóa của nó sẽ tương ứng lớn (và băm đắt tiền để tính toán). Nếu các thuộc tính có thể được liệt kê (ví dụ, các cột trong một đối tượng ORM), thì bạn có thể đơn giản hóa '__key()'; tuy nhiên, bạn vẫn sẽ phải băm mọi giá trị thuộc tính. Không có cách nào thực sự xung quanh chuyện này. –
Điều này sẽ dẫn đến 'AttributeError' khi so sánh một thể hiện của' A' với một thể hiện của hầu hết các lớp khác, bao gồm 'None'. Và nó có thể dẫn đến sai 'True' nếu lớp kia xảy ra có cùng thuộc tính. Nó sẽ không phải là một vấn đề trong hầu hết các trường hợp? Nếu vậy, chúng ta nên tự kiểm tra xem đó là cùng một lớp học? – max