Я предпочитаю, чтобы прослушиватели событий были развернуты модульной функцией, а не сценарием прослушивателя событий уровня document
. Итак, мне нравится ниже. Обратите внимание: вы не можете переадресовать элемент с одним и тем же прослушивателем событий, поэтому не беспокойтесь о прикреплении слушателя более одного раза - только один палец.
var iterations = 4;
var button;
var body = document.querySelector("body");
for (var i = 0; i < iterations; i++) {
button = document.createElement("button");
button.classList.add("my-button");
button.appendChild(document.createTextNode(i));
button.addEventListener("click", myButtonWasClicked);
body.appendChild(button);
}
function myButtonWasClicked(e) {
console.log(e.target); //access to this specific button
}
Я нашел этот Q / A очень интересным, так как он предлагает несколько разных решений для одной и той же проблемы. Я взял все эти функции и протестировал их со сложным словарным объектом. Я должен был взять две функции из теста, потому что им приходилось много неудачных результатов, и они не поддерживали возвращаемые списки или dicts как значения, которые я считаю существенными, так как функция должна быть подготовлена почти для any
Итак, я перекачал другие функции в 100 000 итераций через модуль 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)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Все функции имели одинаковую иглу для поиска («logging») и того же словарного объекта, который строится следующим образом:
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
работают только в том случае, если вы ищете строки.
Интересный аспект обучения здесь:)
def find(key, value):
for k, v in value.iteritems():
if k == key:
yield v
elif isinstance(v, dict):
for result in find(key, v):
yield result
elif isinstance(v, list):
for d in v:
for result in find(key, d):
yield result
isinstance
чек для dict
перед последними двумя строками решает это.
– Matt Swain
21 March 2012 в 18:15
d = { "id" : "abcde",
"key1" : "blah",
"key2" : "blah blah",
"nestedlist" : [
{ "id" : "qwerty",
"nestednestedlist" : [
{ "id" : "xyz", "keyA" : "blah blah blah" },
{ "id" : "fghi", "keyZ" : "blah blah blah" }],
"anothernestednestedlist" : [
{ "id" : "asdf", "keyQ" : "blah blah" },
{ "id" : "yuiop", "keyW" : "blah" }] } ] }
def findkeys(node, kv):
if isinstance(node, list):
for i in node:
for x in findkeys(i, kv):
yield x
elif isinstance(node, dict):
if kv in node:
yield node[kv]
for j in node.values():
for x in findkeys(j, kv):
yield x
print list(findkeys(d, 'id'))
Вот мой удар по нему:
def keyHole(k2b,o):
# print "Checking for %s in "%k2b,o
if isinstance(o, dict):
for k, v in o.iteritems():
if k == k2b and not hasattr(v, '__iter__'): yield v
else:
for r in keyHole(k2b,v): yield r
elif hasattr(o, '__iter__'):
for r in [ keyHole(k2b,i) for i in o ]:
for r2 in r: yield r2
return
>>> findMe = {'Me':{'a':2,'Me':'bop'},'z':{'Me':4}}
>>> keyHole('Me',findMe)
<generator object keyHole at 0x105eccb90>
>>> [ x for x in keyHole('Me',findMe) ]
['bop', 4]
Вот как я это сделал.
Эта функция рекурсивно ищет словарь, содержащий вложенные словари и списки. Он создает список с именем fields_found, который содержит значение для каждого момента поиска поля. «Поле» - это ключ, который я ищу в словаре и его вложенных списках и словарях.
def get_recursively(search_dict, field): """Takes a dict with nested lists and dicts, and searches all dicts for a key of the field provided. """ fields_found = [] for key, value in search_dict.iteritems(): if key == field: fields_found.append(value) elif isinstance(value, dict): results = get_recursively(value, field) for result in results: fields_found.append(result) elif isinstance(value, list): for item in value: if isinstance(item, dict): more_results = get_recursively(item, field) for another_result in more_results: fields_found.append(another_result) return fields_found
Я просто хотел повторить отличный ответ на @ hexerei-software с помощью yield from
и принять списки верхнего уровня.
def gen_dict_extract(var, key):
if isinstance(var, dict):
for k, v in var.items():
if k == key:
yield v
if isinstance(v, (dict, list)):
yield from gen_dict_extract(v, key)
elif isinstance(var, list):
for d in var:
yield from gen_dict_extract(d, key)
Еще одна вариация, которая включает вложенный путь к найденным результатам ( note: эта версия не рассматривает списки ):
def find_all_items(obj, key, keys=None):
"""
Example of use:
d = {'a': 1, 'b': 2, 'c': {'a': 3, 'd': 4, 'e': {'a': 9, 'b': 3}, 'j': {'c': 4}}}
for k, v in find_all_items(d, 'a'):
print "* {} = {} *".format('->'.join(k), v)
"""
ret = []
if not keys:
keys = []
if key in obj:
out_keys = keys + [key]
ret.append((out_keys, obj[key]))
for k, v in obj.items():
if isinstance(v, dict):
found_items = find_all_items(v, key, keys=(keys+[k]))
ret += found_items
return ret
d = { "id" : "abcde",
"key1" : "blah",
"key2" : "blah blah",
"nestedlist" : [
{ "id" : "qwerty",
"nestednestedlist" : [
{ "id" : "xyz", "keyA" : "blah blah blah" },
{ "id" : "fghi", "keyZ" : "blah blah blah" }],
"anothernestednestedlist" : [
{ "id" : "asdf", "keyQ" : "blah blah" },
{ "id" : "yuiop", "keyW" : "blah" }] } ] }
def fun(d):
if 'id' in d:
yield d['id']
for k in d:
if isinstance(d[k], list):
for i in d[k]:
for j in fun(i):
yield j
>>> list(fun(d))
['abcde', 'qwerty', 'xyz', 'fghi', 'asdf', 'yuiop']
for k in d
- for k,value in d.items()
с последующим использованием value
вместо d[k]
.
– ovgolovin
21 March 2012 в 17:49
gen_dict_extract
– Bruno Bronosky
20 February 2017 в 05:24
gen_dict_extract(keys, var)
(2) положитеfor key in keys:
как строка 2 & amp; отступ остальных (3) изменить первый выход наyield {key: v}
– Bruno Bronosky 20 February 2017 в 05:22next(functionname(k, o)
для всех решений генератора. – kaleissin 18 July 2017 в 13:10hasattr(var, 'items')
для python3 – gobrewers14 8 September 2017 в 16:16if hasattr
часть версии, используяtry
, чтобы поймать исключение в случае сбоя вызова (см. pastebin.com/ZXvVtV0g для возможной реализации)? Это уменьшило бы удвоенный поиск атрибутаiteritems
(один раз дляhasattr()
и один раз для вызова), и, следовательно, возможно, сократить время выполнения (что для вас важно). Однако не было никаких контрольных показателей. – Alfe 9 November 2017 в 10:56