Python - сокращение цикла if / for - PullRequest
3 голосов
/ 07 ноября 2011

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

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

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

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

Любой вклад очень ценится

Ответы [ 3 ]

7 голосов
/ 07 ноября 2011

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

devFound = any(d['name'] == devName for d in dev['devices'])
4 голосов
/ 07 ноября 2011

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

any(d for d in dev["devices"] if d['name'] == devName)
1 голос
/ 10 ноября 2011

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

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 …) решение 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        
...