>>> {True: 'yes', 1: 'no', 1.0: 'maybe'}
{True: 'maybe'}
>>> True == 1 == 1.0
True
>>> hash(True), hash(1), hash(1.0)
(1, 1, 1)
>>>
class OnlyEquals:
def __eq__(self, other):
return True
def __hash__(self):
return id(self)
print OnlyEquals() == OnlyEquals() # True
print OnlyEquals() == 42 # True
print OnlyEquals() == 'wait' # True
objects = [OnlyEquals(), OnlyEquals(), OnlyEquals()]
print [hash(o) for o in objects]
# [140525112345520, 140525112345448, 140525112345592]
print {OnlyEquals(): 1, OnlyEquals(): 2}
"""
{
<__main__.OnlyEquals instance at 0x7fee3ab12440>: 1,
<__main__.OnlyEquals instance at 0x7fee3ab12488>: 2
}
"""
class OnlySomeHash:
def __eq__(self, other):
return False
def __hash__(self):
return 1
print OnlySomeHash() == OnlySomeHash() # False
print OnlySomeHash() == 42 # False
print OnlySomeHash() == 'wait' # False
objects = [OnlySomeHash(), OnlySomeHash(), OnlySomeHash()]
print [hash(o) for o in objects]
# [1, 1, 1]
print {OnlySomeHash(): 1, OnlySomeHash(): 2}
"""
{
<__main__.OnlySomeHash instance at 0x7f34a7979440>: 1,
<__main__.OnlySomeHash instance at 0x7f34a7979488>: 2
}
"""
class EqualsAndSomeHash:
def __eq__(self, other):
return True
def __hash__(self):
return 1
print EqualsAndSomeHash() == EqualsAndSomeHash() # True
print EqualsAndSomeHash() == 42 # True
print EqualsAndSomeHash() == 'wait' # True
objects = [EqualsAndSomeHash(), EqualsAndSomeHash(), EqualsAndSomeHash()]
print [hash(o) for o in objects]
# [1, 1, 1]
print {EqualsAndSomeHash(): 1, EqualsAndSomeHash(): 2}
"""
{<__main__.EqualsAndSomeHash instance at 0x7f4e215ab440>: 2}
"""
一个可散列的对象必须满足以下要求:
- 支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的。
- 支持通过 __eq__() 方法来检测相等性。
- 若 a == b 为真, 则 hash(a) == hash(b) 也为真。
Notes:
- 所有由用户自定义的对象默认都是可散列的, 因为它们的散列值由id() 来获取, 而且它们都是不相等的。
- 如果你实现了一个类的 __eq__ 方法, 并且希望它是可散列的, 那么它一定要有个恰当的 __hash__ 方法, 保证在 a == b 为真的情况下 hash(a) == hash(b) 也必定为真。
实现方式 | 是否可 hash | 原因 |
---|---|---|
__hash__(self) 和 __eq__(self, other) 都不实现 | 可 hash | 所有由用户自定义的对象默认都是可散列的, 因为它们的散列值由id() 来获取, 而且它们都是不相等的 |
实现 __hash__(self),不实现__eq__(self, other) | 可 hash | 支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的;所有由用户自定义的对象默认都是不相等的 |
__hash__(self) 和 __eq__(self, other) 都实现 | 可 hash | 支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的; 支持通过 __eq__() 方法来检测相等性;如果你实现了一个类的 __eq__ 方法, 并且希望它是可散列的, 那么它一定要有个恰当的 __hash__ 方法, 保证在 a == b 为真的情况下 hash(a) == hash(b) 也必定为真 |
不实现__hash__(self), 实现__eq__(self, other) | 不可 hash | 如果你实现了一个类的 __eq__ 方法, 并且希望它是可散列的, 那么它一定要有个恰当的 __hash__ 方法, 保证在 a == b 为真的情况下 hash(a) == hash(b) 也必定为真 |
- __hash__(self) 和 __eq__(self, other) 都不实现
- 所有由用户自定义的对象默认都是可散列的, 因为它们的散列值由id() 来获取, 而且它们都是不相等的
- 实现 __hash__(self),不实现 __eq__(self, other)
- 支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的
- 所有由用户自定义的对象默认都是不相等的
- __hash__(self) 和 __eq__(self, other) 都实现
- 支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的
- 支持通过 __eq__() 方法来检测相等性
- 如果你实现了一个类的 __eq__ 方法, 并且希望它是可散列的, 那么它一定要有个恰当的 __hash__ 方法, 保证在 a == b 为真的情况下 hash(a) == hash(b) 也必定为真
如果只实现 __eq__(self, other),不实现 __hash__(self),则对象不可hash
#!/usr/bin/env python
# -*- coding: utf-8 -*-
class C1:
''' __hash__(self) 和 __eq__(self, other) 都不实现
所有由用户自定义的对象默认都是可散列的, 因为它们的散列值由id() 来获取, 而且它们都是不相等的
'''
def __init__(self, x):
self.x = x
print hash(C1(1)) # 8736312111280
class C2:
'''实现 __hash__(self),不实现 __eq__(self, other)
支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的
所有由用户自定义的对象默认都是不相等的
'''
def __init__(self, x):
self.x = x
def __hash__(self):
return hash(self.x)
print hash(C2(1)) # 1
class C3:
''' __hash__(self) 和 __eq__(self, other) 都实现
支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的
支持通过 __eq__() 方法来检测相等性
如果你实现了一个类的 __eq__ 方法, 并且希望它是可散列的, 那么它一定要有个恰当的 __hash__ 方法, 保证在 a == b 为真的情况下 hash(a) == hash(b) 也必定为真
'''
def __init__(self, x):
self.x = x
def __hash__(self):
return hash(self.x)
def __eq__(self, other):
return (
self.__class__ == other.__class__ and
self.x == other.x
)
print hash(C3(1)) # 1
class C4:
'''只实现 __eq__(self, other),不实现 __hash__(self)
'''
def __init__(self, x):
self.x = x
def __eq__(self, other):
return (
self.__class__ == other.__class__ and
self.x == other.x
)
print hash(C4(1)) # TypeError: unhashable instance
对象作为key值则对象必须可hash
hash | equality | 是否可以作为同样的key |
---|---|---|
相同 | 相等 | 同一个key |
相同 | 不相等 | 不同的key |
不相同 | 相等 | 不可 hash, 不能作为key |
不相同 | 不相等 | 不同的key |
#!/usr/bin/env python
# -*- coding: utf-8 -*-
class C1:
''' __hash__(self) 和 __eq__(self, other) 都不实现
所有由用户自定义的对象默认都是可散列的, 因为它们的散列值由id() 来获取, 而且它们都是不相等的
'''
def __init__(self, x):
self.x = x
# 测试是否可hash
print hash(C1(1)) # 8728643443659
# 对象是否可以作为set或者dictionary的key
obj1 = C1(1)
obj2 = C1(1)
print hash(obj1), hash(obj2) # 8728643443659 -9223363308211332145
print obj1 == obj2 # False
s = set()
s.add(obj1)
s.add(obj2)
print len(s) # 2
print '************' * 10
class C2:
'''实现 __hash__(self),不实现 __eq__(self, other)
支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的
所有由用户自定义的对象默认都是不相等的
'''
def __init__(self, x):
self.x = x
def __hash__(self):
return hash(self.x)
# 测试是否可hash
print hash(C2(1)) # 1
# 对象是否可以作为set或者dictionary的key
obj1 = C2(1)
obj2 = C2(1)
print hash(obj1), hash(obj2) # 1 1
print obj1 == obj2 # False
s = set()
s.add(obj1)
s.add(obj2)
print len(s) # 2
print '************' * 10
class C3:
''' __hash__(self) 和 __eq__(self, other) 都实现
支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的
支持通过 __eq__() 方法来检测相等性
如果你实现了一个类的 __eq__ 方法, 并且希望它是可散列的, 那么它一定要有个恰当的 __hash__ 方法, 保证在 a == b 为真的情况下 hash(a) == hash(b) 也必定为真
'''
def __init__(self, x):
self.x = x
def __hash__(self):
return hash(self.x)
def __eq__(self, other):
return (
self.__class__ == other.__class__ and
self.x == other.x
)
# 测试是否可hash
print hash(C3(1)) # 1
# 对象是否可以作为set或者dictionary的key
obj1 = C3(1)
obj2 = C3(1)
print hash(obj1), hash(obj2) # 1 1
print obj1 == obj2 # True
s = set()
s.add(obj1)
s.add(obj2)
print len(s) # 1
print '************' * 10
class C4:
'''只实现 __eq__(self, other),不实现 __hash__(self)
'''
def __init__(self, x):
self.x = x
def __eq__(self, other):
return (
self.__class__ == other.__class__ and
self.x == other.x
)
# 测试是否可hash
# print hash(C4(1)) # TypeError: unhashable instance
# 对象是否可以作为set或者dictionary的key
obj1 = C4(1)
obj2 = C4(1)
# print hash(obj1), hash(obj2) # TypeError: unhashable instance
print obj1 == obj2 # True
s = set()
# s.add(obj1) # TypeError: unhashable instance
# s.add(obj2) # TypeError: unhashable instance
print len(s) # 0
print '************' * 10
#!/usr/bin/env python
# -*- coding: utf-8 -*-
class C:
def __init__(self, x):
self.x = x
def __hash__(self):
return hash(self.x)
def __eq__(self, other):
return (self.__class__ == other.__class__ and self.x == other.x)
d = dict()
s = set()
c1 = C(1)
print hash(c1) # 1
# 对象c1可hash,可以作为set和dictionary的key值
d[c1] = 42
s.add(c1)
print c1 in s # True
print c1 in d # True
c1.x = 2
print hash(c1) # 2
# 对象c1的hash值在生命周期内发生变化,变化后将不能作为set和dictionary的key值
print c1 in s # False
print c1 in d # False
- An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() or __cmp__() method).
- Hashable objects which compare equal must have the same hash value.
- Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.
- All of Python’s immutable built-in objects are hashable, while no mutable containers (such as lists or dictionaries) are.
- Objects which are instances of user-defined classes are hashable by default; they all compare unequal, and their hash value is their id().
- If two objects are equal, then their hashes should be equal.
- If two objects have the same hash, then they are likely to be the same object.