Одна строка для цикла над итератором с фильтром "если"? - PullRequest
52 голосов
/ 08 марта 2010

Глупый вопрос:
У меня есть простой цикл for, за которым следует простое выражение if:

for airport in airports:
    if airport.is_important:

, и мне было интересно, могу ли я как-то написать это в одной строке.
Итакда, я могу сделать это:

for airport in (airport for airport in airports if airport.is_important):

, но это выглядит так глупо и избыточно (for airport in airport for airport in airports...).
Есть ли лучший способ?

Ответы [ 7 ]

70 голосов
/ 08 марта 2010

Нет, более короткого пути нет. Обычно вы даже разбиваете его на две строки:

important_airports = (airport for airport in airports if airport.is_important)
for airport in important_airports:
    # do stuff

Это более гибко, легче для чтения и при этом не занимает много памяти.

28 голосов
/ 08 марта 2010

Вы могли бы сделать

for airport in filter(lamdba x: x.is_important, airports):
    # do stuff...
15 голосов
/ 08 марта 2010

Я бы использовал отрицательную охрану в цикле. Он читабелен и не вводит дополнительный уровень отступов.

for airport in airports:
    if not airport.is_important: continue
    <body of loop>
5 голосов
/ 08 марта 2010

Mabe это, но это более или менее тот же многословный ...

import itertools

for airport in itertools.ifilter(lambda x: x.is_important, airports):
    ...
2 голосов
/ 08 марта 2010

Это философия дизайна Python. Если вам нужно слишком много слов, чтобы поместить его в одну строку, его нужно разбить на несколько строк, чтобы помочь человеку, который идет за вами. Выражения списков и генераторов предназначены для преобразования итеративных элементов на месте, делая более читабельными формы map и filter.

.
1 голос
/ 11 сентября 2013

Вот альтернатива некоторым другим версиям фильтра:

from operator import attrgetter as attr
for airport in filter(attr('is_important'), airports):
    ...

Преимущества этого подхода в том, что он довольно лаконичен, а также позволяет использовать точечную нотацию attr ('first_class.is_full').

Вы также можете поместить что-то подобное (или версию, использующую понимание списка) в служебную функцию, такую ​​как filter_by_attr. Тогда вы могли бы сделать:

for airport in filter_by_attr(airports, 'is_important'):
    ...

Я по-прежнему считаю, что e-satuns правильно помещать ее в новую переменную, независимо от того, какой метод вы используете. Это становится более понятным, особенно если использование не совсем соответствует названию рассматриваемого атрибута (или критерии более сложные).

Мое единственное замечание по этому поводу заключается в том, что если вы обнаружите, что используете это в нескольких местах, возможно, вам следует сделать аэропорты специальной коллекцией, в которой «Important_airports» является @property, который возвращает отфильтрованную коллекцию. Или какая-то другая абстракция, чтобы скрыть фильтрацию (например, вызов службы).

0 голосов
/ 08 марта 2010

Использование понимания списка (только если аэропорты - это список объектов):

for airport in [a for a in airports if a.is_important]:
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...