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_recursivley
enquanto o resto, exceto dict_extract
, está perto um do outro. As funções fun
e keyHole
só funcionam se você estiver procurando por strings.
Aspecto de aprendizagem interessante aqui :)