Wydaje mi się, że to pytanie / odpowiedzi jest bardzo interesujące, ponieważ zawiera kilka różnych rozwiązań tego samego problemu. Wziąłem wszystkie te funkcje i przetestowałem je na złożonym obiekcie słownikowym. Musiałem usunąć dwie funkcje z testu, ponieważ miały wiele wyników niepowodzeń i nie obsługiwały zwracania list lub dyktowania jako wartości, co uważam za niezbędne, ponieważ funkcja powinna być przygotowana dla prawie wszystkich danych, które mają nadejść.
Więc przepompowałem inne funkcje w 100.000 iteracjach przez timeit
moduł i wyjście dało następujący wynik:
0.11 usec/pass on gen_dict_extract(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
6.03 usec/pass on find_all_items(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0.15 usec/pass on findkeys(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1.79 usec/pass on get_recursively(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0.14 usec/pass on find(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0.36 usec/pass on dict_extract(k,o)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Wszystkie funkcje miały tę samą igłę do wyszukiwania („logowanie”) i ten sam obiekt słownikowy, który jest zbudowany w następujący sposób:
o = { 'temparature': '50',
'logging': {
'handlers': {
'console': {
'formatter': 'simple',
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout',
'level': 'DEBUG'
}
},
'loggers': {
'simpleExample': {
'handlers': ['console'],
'propagate': 'no',
'level': 'INFO'
},
'root': {
'handlers': ['console'],
'level': 'DEBUG'
}
},
'version': '1',
'formatters': {
'simple': {
'datefmt': "'%Y-%m-%d %H:%M:%S'",
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
}
}
},
'treatment': {'second': 5, 'last': 4, 'first': 4},
'treatment_plan': [[4, 5, 4], [4, 5, 4], [5, 5, 5]]
}
Wszystkie funkcje dały ten sam wynik, ale różnice czasowe są dramatyczne! Funkcja gen_dict_extract(k,o)
jest moją funkcją zaadaptowaną z funkcji tutaj, w rzeczywistości jest prawie podobna do find
funkcji z Alfe, z tą główną różnicą, że sprawdzam, czy dany obiekt ma funkcję iteritems, w przypadku, gdy ciągi są przekazywane podczas rekurencji:
def gen_dict_extract(key, var):
if hasattr(var,'iteritems'):
for k, v in var.iteritems():
if k == key:
yield v
if isinstance(v, dict):
for result in gen_dict_extract(key, v):
yield result
elif isinstance(v, list):
for d in v:
for result in gen_dict_extract(key, d):
yield result
Więc ten wariant jest najszybszą i najbezpieczniejszą z funkcji tutaj. I find_all_items
jest niesamowicie powolny i daleko od drugiego najwolniejszego, get_recursivley
podczas gdy reszta, z wyjątkiem dict_extract
, jest blisko siebie. Funkcje fun
i keyHole
działają tylko wtedy, gdy szukasz ciągów.
Ciekawy aspekt uczenia się tutaj :)