[Antecedentes del problema] Personalicé el tipo de objeto. Cuando usé set () para juzgar el peso, descubrí que la sobrecarga __eq__
no funcionaba. Siempre pensé que era diferente.
[Causa del problema] Cuando se utiliza un objeto personalizado como un elemento de colección set (), debido a que el conjunto pertenece a la estructura de datos del algoritmo hash, el hash se juzga primero al juzgar el peso, y solo cuando el hash es el mismo Sigue siendo llamado __eq__
a juzgar el peso. Lo mismo es cierto para otras estructuras de datos hash.
1. Cuando se __hash__
llama al método mágico
Tenga en cuenta que este __hash__
método mágico:
(1) Llamado por la función incorporada hash ()
(2) un conjunto de hash de tipo de hash propio miembro de operación: set()
, frozenset([iterable])
,dict(**kwarg)
2 Ejemplos de escenarios de aplicación
2.1 Solo use el __eq__
juicio, no es necesario sobrecargar__hash__
Solo se llamará cuando los objetos se comparen utilizando el símbolo de paridad __eq__
. En este momento, __hash__
se puede obtener el resultado correcto sin sobrecargar :
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Student(object):
def __init__(self, name, age):
self._name = name
self._age = age
def __hash__(self):
print 'Call __hash__'
def __eq__(self, other):
print 'Call __eq__'
if not isinstance(other, Student):
return False
return self._name == other._name and self._age == other._age
if __name__ == '__main__':
s1 = Student('aa', 20)
s2 = Student('aa', 20)
s3 = Student('bb', 21)
print s1 == s2
print s1 == s3
2.2 Estrategia de comparación de la estructura hash
En la versión de la serie Python3.X, si solo está personalizado __eq__
pero no definido __hash__
, el Objeto no se puede usar como un elemento de estructura de datos hash (set, frozenset, dict). Porque en este momento automáticamente dejamos __hash__
regresar Ninguno;
En la serie Python2.X, si solo se personaliza __eq__
pero no se define __hash__
, aún se puede usar como un elemento de estructura de datos hash (set, frozenset, dict). En este momento, causará un error en la comparación. Las razones son como sigue:
(1) La estructura hash primero llama al __hash__
Objeto de comparación. La generación del valor hash predeterminado es diferente (relacionada con la dirección), por lo que siempre juzgará que los dos Objetos no son iguales, incluso si las asignaciones internas son las mismas;
(2) Cuando la estructura hash es __hash__
igual, se seguirá llamando a la __eq__
comparación.
class Student(object):
def __init__(self, name, age):
self._name = name
self._age = age
def __hash__(self):
print 'Call __hash__'
return hash(self._name + str(self._age)) # 请注意这里一定要返回hash值,否则None报错
def __eq__(self, other):
print 'Call __eq__'
if not isinstance(other, Student):
return False
return self._name == other._name and self._age == other._age
if __name__ == '__main__':
s1 = Student('aa', 20)
s2 = Student('aa', 20)
s3 = Student('bb', 21)
test_set = set()
test_set.add(s1)
print s2 in test_set # True
print s3 in test_set # False