Achei esta Q / A muito interessante, pois fornece várias soluções diferentes para o mesmo problema. Peguei todas essas funções e testei-as com um objeto de dicionário complexo. Tive que retirar duas funções do teste, porque eles tiveram muitos resultados reprovados e não suportavam o retorno de listas ou dictos como valores, o que considero essencial, uma vez que uma função deve ser preparada para quase todos os dados que virão.
Então eu bombeei as outras funções em 100.000 iterações através do timeit módulo e a saída veio para o seguinte resultado:
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)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Todas as funções tinham o mesmo ponteiro para pesquisar ('logging') e o mesmo objeto de dicionário, que é construído assim:
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]]
}
Todas as funções forneceram o mesmo resultado, mas as diferenças de tempo são dramáticas! A função gen_dict_extract(k,o)é a minha função adaptada das funções aqui, na verdade é muito parecida com ofind função de Alfe, com a principal diferença, que estou verificando se o objeto fornecido tem função de iteritens, no caso de strings serem passadas durante a recursão:
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
Portanto, esta variante é a mais rápida e segura das funções aqui. E find_all_itemsé incrivelmente lento e distante do segundo mais lento get_recursivleyenquanto o resto, exceto dict_extract, está perto um do outro. As funções fune keyHolesó funcionam se você estiver procurando por strings.
Aspecto de aprendizagem interessante aqui :)