子类化`int`时不可用的类型

时间:2015-12-21 11:24:18

标签: python

让我们定义一个非常简单的Test类,它继承自int

TEST_DICT = {1: 'a', 2: 'b'}


class Test(int):

    def __str__(self):
        return TEST_DICT[self]

    def __repr__(self):
        return str(self)


if __name__ == '__main__':
    print(Test(1))

这将按预期打印a,即1Test的代表。

现在,让我们重新定义__eq__方法:

TEST_DICT = {1: 'a', 2: 'b'}


class Test(int):

    def __str__(self):
        return TEST_DICT[self]

    def __repr__(self):
        return str(self)

    def __eq__(self, other):
        if isinstance(other, int):
            return self == other
        if isinstance(other, str):
            return str(self) == other
        return False


if __name__ == '__main__':
    print(Test(1))

然而,这导致以下追溯:

Traceback (most recent call last):
  File "test.py", line 14, in <module>
    print(Test(1))
  File "test.py", line 4, in __str__
    return TEST_DICT[self]
TypeError: unhashable type: 'Test'

有人可以解释为什么会发生这种情况,我怎么能避免这个错误,同时还能重新定义__eq__方法?

2 个答案:

答案 0 :(得分:3)

来自https://docs.python.org/2/reference/datamodel.html

  

这里没有比较运算符之间的隐含关系。 x == y的真实性并不意味着x!= y是假的。因此,在定义 eq ()时,还应该定义 ne (),以便运算符按预期运行。有关创建支持自定义比较操作的可哈希对象的一些重要说明,请参阅哈希()上的段落。

  

如果某个类未定义 cmp ()或 eq ()方法,则不应定义哈希()操作; 如果它定义__cmp __()或__eq __()但不定义__hash __(),则它的实例将无法在散列集合中使用。如果类定义了可变对象并实现了 cmp ()或 eq ()方法,它不应该实现哈希(),因为hashable collection实现要求对象的哈希值是不可变的(如果对象的哈希值发生变化,它将在错误的哈希桶中。)

     

默认情况下,用户定义的类具有 cmp ()和哈希()方法;使用它们,所有对象都比较不相等(除了它们自己)和x。哈希()返回从id(x)派生的结果。

答案 1 :(得分:0)

感谢@DeepSpace提供有关数据模型文档的链接。

可能的实施,供参考:

TEST_DICT = {1: 'a', 2: 'b'}


class Test(int):

    def __str__(self):
        return TEST_DICT[int(self)]

    def __repr__(self):
        return str(self)

    def __eq__(self, other):
        if isinstance(other, int):
            return int(self) == other
        if isinstance(other, str):
            return str(self) == other
        return False

    def __hash__(self):
        return hash(int(self))


if __name__ == '__main__':
    print(Test(1))

请注意int(self)__eq__()中的转化__hash__(),以避免无限递归。