我有一个其实例要通过与它们所携带的数据值不同的标识来区分的类。在我的代码中,我打算用==
表示两个实例在数据上是等效的,并且is
表示两个变量引用相同的实例,即它们是相同的。据我了解,这都是很正常的。
此外,我想在set
s中使用实例(等效或否),并在dict
s中用作键。这要求为该类定义__hash__
函数。
但是在这一点上,我不理解__hash__
的书面要求:
唯一需要的属性是比较相等的对象具有相同的哈希值。
这是否意味着不能将两个不同但等效的对象用作dict
中的不同键,或不能单独出现在set
中?在下面的代码中,我通过覆盖__eq__
和__hash__
来反映我的预期用途,从而打破了这一要求。它可以在Python 2.7和3.7中正常工作。
如我在这里所做的,违反__hash__
的要求有什么负面影响?
有没有更好的方法可以实现我的目标?
class A( object ):
def __init__( self, v1, v2 ):
self.v = ( v1, v2 )
def __eq__( self, b ):
return self.v[0] == b.v[0] and self.v[1] == b.v[1]
def __hash__( self ):
return id( self )
def __str__( self ):
return str( self.v )
p = A( 1, 0 )
q = A( 1, 0 )
print( str( p ), str( q ) )
print( "identical?", p is q )
print( "equivalent?", p == q )
print( "hashes", hash(p), hash(q) )
s = set( [p, q] )
print( "set length", len( s ) )
print( "both in set?", p in s, q in s )
d = { p:3, q:4 }
print( "dict length", len( d ) )
print( "as distinct keys", d[p], d[q] )
您应该使用id
派生类实例的哈希值。引用自docs:
作为用户定义类实例的对象默认情况下是可哈希的。它们都比较不相等(除了它们本身),并且其哈希值从其id()派生。