Я нашел этот вопрос / ответ очень интересным, поскольку он предлагает несколько различных решений одной и той же проблемы. Я взял все эти функции и протестировал их со сложным словарным объектом. Мне пришлось исключить две функции из теста, потому что у них было много неудачных результатов, и они не поддерживали возвращение списков или диктов в качестве значений, что я считаю важным, поскольку функция должна быть подготовлена практически для любых данных.
Итак, я прокачал другие функции за 100000 итераций через timeit
модуль, и на выходе получился следующий результат:
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)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
У всех функций была одна и та же стрелка для поиска ('ведение журнала') и один и тот же объект словаря, который построен следующим образом:
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]]
}
Все функции дали одинаковый результат, но разница во времени огромна! Функция gen_dict_extract(k,o)
- это моя функция, адаптированная из приведенных здесь функций, на самом деле она очень похожа на find
функцию из Alfe, с основным отличием, что я проверяю, имеет ли данный объект функцию iteritems, в случае, если строки передаются во время рекурсии:
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
Таким образом, этот вариант является самым быстрым и безопасным из имеющихся здесь функций. И find_all_items
он невероятно медленный и далеко от второго по скорости, в get_recursivley
то время как остальные, за исключением dict_extract
, близки друг к другу. Функции fun
и keyHole
работают только в том случае, если вы ищете строки.
Интересный аспект обучения :)