在将一些代码从python 2转换为python 3时,我遇到了一个奇怪的行为示例。下面是一个最小的(?)示例:
class Bar(object):
def __init__(self, x):
self.x = x
def __eq__(self, other):
return self.x == other.x
b = Bar(1)
print(hash(b))
当使用python2
运行时,此代码产生一些输出(Bar(1)
的散列),而python3
导致TypeError: unhashable type: 'Bar'
这意味着__hash__
在python 2中以某种方式继承(来自object
?)。
所以,我的问题是:python 2中Bar(1)
的哈希是什么?为什么行为不同?
是的,数据模型已经改变。 In Python 3:
用户定义的类默认具有
__eq__()
和__hash__()
方法;与它们相比,所有对象都比较不等(除了它们自己)和x.__hash__()
返回一个合适的值,使得x == y
暗示x is y
和hash(x) == hash(y)
。一个覆盖
__eq__()
并且没有定义__hash__()
的类将其__hash__()
隐式设置为None
。当类的__hash__()
方法是None
时,类的实例将在程序尝试检索其哈希值时引发适当的TypeError,并且在检查isinstance(obj, collections.abc.Hashable)
时也将被正确识别为不可用。
所以,既然你已经明确地定义了一个qazxsw poi,但没有定义一个qazxsw poi,那么Python 3对象将隐含地拥有__eq__
,导致对象不可用
在__hash__
:
用户定义的类默认具有
__hash__ = None
和Python 2方法;与它们相比,所有对象都比较不等(除了自己),__cmp__()
返回从__hash__()
派生的结果。
所以它是基于身份的散列,这是一个问题,因为它与你的x.__hash__()
不一致。这是Python 3切换行为的原因。
来自id(x)
重写eq()并且未定义hash()的类将使其hash()隐式设置为None。当类的hash()方法为None时,类的实例将在程序尝试检索其哈希值时引发适当的TypeError,并且在检查isinstance时也将被正确识别为不可用(obj,collections.abc.Hashable )。
有关Python 2版本,请参阅__eq__
。