Python – сокращение цикла if / for

У меня есть несколько строк кода для итерации над dict в списке, и я хочу сократить его. Он работает отлично, как есть, но кажется, что слишком много кода, и я пытаюсь понять, как сохранить код в Python (или вообще на самом деле).

for d in dev['devices']: if d['name'] == devName: devFound = True break 

Структура «dev» немного запутанна, но для данных, которые мне волнуют: dev (dict)> devices (list)> 0-n (dict)

значение «имя» является ключом внутри внутреннего пронумерованного dict (зависит от значения поиска в другом месте), который необходимо проверить на пользовательском вводе (devName)

Любой вход, который очень ценится

    В основном то же самое, только переписанное с некоторой встроенной функцией и генератором:

     devFound = any(d['name'] == devName for d in dev['devices']) 

    вы можете попробовать с функцией any () :

     any(d for d in dev["devices"] if d['name'] == devName) 

    Вот вариант ответа Седрика Жюльена, потому что он может потерпеть неудачу в некоторых (редких) случаях:

     any(True for d in dev["devices"] if d['name'] == devName) 

    Вот (по общему признанию, необычный, но возможный) случай, который иллюстрирует, пока any(True …) дает правильный результат, в то время как any(d …) не делает:

     >>> class special_dict(dict): ... def __nonzero__(self): ... return False # All special_dict objects are False ... >>> dev = {'devices': [special_dict(name="DEVNAME") for _ in xrange(10)]} >>> any(d for d in dev["devices"] if d['name'] == "DEVNAME") # Incorrect False >>> any(True for d in dev["devices"] if d['name'] == "DEVNAME") # Correct True 

    Фактически объекты special_dict оцениваются как False, поэтому нет смысла тестировать значение истины d в any() . Однако использование True работает.

    PS : Временные тесты показывают, что any(True … for … if … == …) подход быстрее, чем any(… == … for …) другое any(… == … for …) решение doublep:

     python -m timeit -s "dev = {'devices': [{'name': 'BADNAME'} for _ in xrange(100)]}" "any(d['name'] == 'DEVNAME' for d in dev['devices'])" 100000 loops, best of 3: 16.3 usec per loop python -m timeit -s "dev = {'devices': [{'name': 'BADNAME'} for _ in xrange(100)]}" "any(True for d in dev['devices'] if d['name'] == 'DEVNAME' )" 100000 loops, best of 3: 9.42 usec per loop 

    Причина в том, что второй генератор возвращает не более одного значения (True). Это можно увидеть, разобрав код Python для двух генераторов:

     In [8]: def f(my_list): ...: return any(x == 11 for x in my_list) In [12]: f.func_code.co_consts[1] Out[12]: <code object <genexpr> at 0x1041f98b0, file "<ipython-input-8-384ce7986872>", line 2> In [13]: dis.dis(_) 2 0 LOAD_FAST 0 (.0) >> 3 FOR_ITER 17 (to 23) 6 STORE_FAST 1 (x) 9 LOAD_FAST 1 (x) 12 LOAD_CONST 0 (11) 15 COMPARE_OP 2 (==) 18 YIELD_VALUE 19 POP_TOP 20 JUMP_ABSOLUTE 3 >> 23 LOAD_CONST 1 (None) 26 RETURN_VALUE 

    Этот код содержит YIELD_VALUE и POP_TOP , которые занимают дополнительное время по сравнению с версией этого ответа:

     In [14]: def g(my_list): ....: return any(True for x in my_list if x == 11) In [15]: g.func_code.co_consts[1] Out[15]: <code object <genexpr> at 0x1041f9630, file "<ipython-input-14-735c68947d80>", line 2> In [16]: dis.dis(g.func_code.co_consts[1]) 2 0 LOAD_FAST 0 (.0) >> 3 FOR_ITER 23 (to 29) 6 STORE_FAST 1 (x) 9 LOAD_FAST 1 (x) 12 LOAD_CONST 0 (11) 15 COMPARE_OP 2 (==) 18 POP_JUMP_IF_FALSE 3 21 LOAD_GLOBAL 0 (True) 24 YIELD_VALUE 25 POP_TOP 26 JUMP_ABSOLUTE 3 >> 29 LOAD_CONST 1 (None) 32 RETURN_VALUE