Digamos que tengo dos diccionarios y quiero medir el tiempo necesario para comprobar si hay una clave en el diccionario. Intenté ejecutar este fragmento de código:
from timeit import timeit dct1 = {str(i): 1 for i in range(10**7)} dct2 = {i: 1 for i in range(10**7)} print(timeit('"7" in dct1', setup='from __main__ import dct1', number=10**8)) print(timeit('7 in dct2', setup='from __main__ import dct2', number=10**8))Aquí están los resultados que obtengo:
2.529034548999334 2.212983401999736Ahora, digamos que trato de mezclar números enteros y cadenas en ambos diccionarios y medir el tiempo de acceso nuevamente:
dct1[7] = 1 dct2["7"] = 1 print(timeit('"7" in dct1', setup='from __main__ import dct1', number=10**8)) print(timeit('7 in dct1', setup='from __main__ import dct1', number=10**8)) print(timeit('7 in dct2', setup='from __main__ import dct2', number=10**8)) print(timeit('"7" in dct2', setup='from __main__ import dct2', number=10**8))me sale algo raro:
3.443614432000686 2.6335261530002754 2.1873921409987815 2.272667104998618El primer valor es mucho más alto que el que tenía antes (3.44 vs 2.52). Sin embargo, el tercer valor es básicamente el mismo que antes (2,18 frente a 2,21). ¿Por qué está pasando esto? ¿Puedes reproducir lo mismo o solo soy yo? Además, no puedo entender la gran diferencia entre el primer y el segundo valor: parece que es más difícil acceder a una clave de cadena, pero lo mismo parece aplicarse solo ligeramente al segundo diccionario. ¿Por qué?
Actualizar
Ni siquiera necesita agregar una nueva clave. ¡Todo lo que necesita hacer para ver un aumento en la complejidad es verificar si existe una clave con un tipo diferente! Esto es mucho más raro de lo que pensaba. Mira el ejemplo aquí:
from timeit import timeit dct1 = {str(i): 1 for i in range(10**7)} dct2 = {i: 1 for i in range(10**7)} print(timeit('"7" in dct1', setup='from __main__ import dct1', number=10**8)) # 2.55 print(timeit('7 in dct2', setup='from __main__ import dct2', number=10**8)) # 2.26 7 in dct1 "7" in dct2 print(timeit('"7" in dct1', setup='from __main__ import dct1', number=10**8)) # 3.34 print(timeit('7 in dct2', setup='from __main__ import dct2', number=10**8)) # 2.35Déjame tratar de responder a mi propia pregunta. La implementación de dict en CPython está optimizada para búsquedas de claves str. De hecho, hay dos funciones diferentes que se utilizan para realizar búsquedas:
lookdict es una función de búsqueda de diccionario genérica que se usa con todo tipo de claveslookdict_unicode es una función de búsqueda especializada que se utiliza para diccionarios compuestos por claves de solo strPython usará la versión optimizada para cadenas hasta una búsqueda de datos que no sean cadenas, después de lo cual se usa la función más general.
Y parece que ni siquiera puede revertir el comportamiento de una instancia de dictado en particular: una vez que comienza a usar la función genérica, ¡no puede volver a usar la función especializada!