mi primera vez publicar aquí, así que espero haber hecho mi pregunta en el tipo derecho de paso,colisiones recuento en un diccionario de Python
Después de añadir un elemento a un diccionario de Python, es posible conseguir a Python ¿Te dicen si agregar ese elemento causó una colisión? (¿Y cuántas ubicaciones exploró la estrategia de resolución de colisiones antes de encontrar un lugar para colocar el elemento?)
Mi problema es: estoy usando diccionarios como parte de un proyecto más grande, y después de un perfil extenso, descubrí que el más lento parte del código trata con una matriz de distancia dispersa implementada usando diccionarios.
Las claves que estoy usando son ID de objetos de Python, que son enteros únicos, por lo que sé que todos los hash a diferentes valores. Pero ponerlos en un diccionario aún podría causar colisiones en principio. No creo que las colisiones en el diccionario sean lo que ralentiza mi programa, pero quiero eliminarlas de mis consultas.
Así, por ejemplo, dada la siguiente diccionario:
d = {}
for i in xrange(15000):
d[random.randint(15000000, 18000000)] = 0
puede usted conseguir Python que le diga cuántas colisiones que sucedió cuando se crea?
Mi código real está enredado con la aplicación, pero el código anterior hace un diccionario que se ve muy similar a los que estoy usando.
Repetir: no creo que las colisiones sean lo que está ralentizando mi código, solo quiero eliminar la posibilidad al mostrar que mis diccionarios no tienen muchas colisiones.
Gracias por su ayuda.
Editar: Algunos código para implementar la solución de @Winston Ewert:
n = 1500
global collision_count
collision_count = 0
class Foo():
def __eq__(self, other):
global collision_count
collision_count += 1
return id(self) == id(other)
def __hash__(self):
#return id(self) # @John Machin: yes, I know!
return 1
objects = [Foo() for i in xrange(n)]
d = {}
for o in objects:
d[o] = 1
print collision_count
Tenga en cuenta que cuando se define __eq__
en una clase, Python le da una TypeError: unhashable instance
si no también define una función __hash__
.
No funciona como esperaba. Si tiene la función __hash__
return 1
, entonces se producen muchas colisiones, como se esperaba (1125560 colisiones para n = 1500 en mi sistema). Pero con return id(self)
, hay 0 colisiones.
¿Alguien sabe por qué esto dice 0 colisiones?
Editar: Pude haber descubierto esto.
¿Es porque __eq__
solo se llama si los valores de dos objetos son los mismos, no su "versión crujiente" (como dijo @John Machin)?
Quiere decir que quiere saber si los algoritmos dict internos hicieron alguna prueba de tabla hash para encontrar un elemento? ¿Es eso lo que quieres decir con "colisión"? –
Información semi-relevante: 'hash (-1) == hash (-2)'. Aparte de eso, todas las entradas x en el intervalo '-sys.maxint-1 <= x <= sys.maxint' tienen hashes únicos. El algoritmo para hash long ints se describe aquí: http://effbot.org/zone/python-hash.htm – unutbu
"El valor hash -1 está reservado (se usa para señalar errores en la implementación C). Si el hash el algoritmo genera este valor, simplemente usamos -2 en su lugar ". Ay. – UncleZeiv