0%

Python连接池

当我自定义类时,如果定义了__eq__方法,这个类的对象会变成unhashable。以下是在python3.6中的情况:

1
2
3
4
5
6
7
8
9
10
11
12
>>> class Item:
... def __init__(self, name):
... self.name = name
... def __eq__(self, other):
... if not isinstance(other, self.__class__):
... return False
... return self.name == other.name
...
>>> {Item('a'): 1}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Item'

排查

以下内容引用自python3手册的object.__hash__部分

If a class does not define an __eq__() method it should not define a __hash__() operation either; if it defines __eq__() but not __hash__(), its instances will not be usable as items in hashable collections. If a class defines mutable objects and implements an __eq__() method, it should not implement __hash__(), since the implementation of hashable collections requires that a keys hash value is immutable (if the objects hash value changes, it will be in the wrong hash bucket).

翻译成中文如下:

如果一个类没有定义__eq __()方法,那么它也不应该定义__hash __()操作。如果它定义__eq __()但不定义__hash __(),则其实例将不能用作可哈希集合中的项目。如果一个类定义了可变对象并实现了__eq __()方法,则不应实现__hash __(),因为可哈希集合的实现要求键的哈希值是不可变的(如果对象的哈希值发生变化,那将是错误的哈希存储桶)

综上,如果定义 __eq__,默认的__hash__ 将消失。

这是因为相等对象的哈希值一定相等,如果__hash__不消失,则会出现相等对象的哈希值不相等的情况。

解决

解决方法很简单,在定义__eq__方法的同时定义__hash__方法即可,如下:

1
2
3
4
5
6
7
8
9
10
11
>>> class Item:
... def __init__(self, name):
... self.name = name
... def __eq__(self, other):
... if not isinstance(other, self.__class__):
... return False
... return self.name == other.name
... def __hash__(self):
... return hash(self.name)
...
>>> {Item('a'): 1}