Подтвердить что ты не робот

Одиночная линия для цикла через итератор с фильтром "if"?

Глупый вопрос:
У меня есть простой цикл, за которым следует простая инструкция 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...).
Есть ли лучший способ?

4b9b3361

Ответ 1

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

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

Это более гибкое, удобное для чтения и все еще не потребляет много памяти.

Ответ 2

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

for airport in filter(lamdba x: x.is_important, airports):
    # do stuff...

Ответ 3

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

for airport in airports:
    if not airport.is_important: continue
    <body of loop>

Ответ 4

Мабе это, но это более или менее такая же многословная...

import itertools

for airport in itertools.ifilter(lambda x: x.is_important, airports):
    ...

Ответ 5

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

Ответ 6

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

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-satis прав, чтобы поместить его в новую переменную независимо от используемого вами метода. Это просто более понятно, особенно если использование точно не соответствует названию рассматриваемого атрибута (или критерии более сложны).

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

Ответ 7

Использование подсчета списков (только если аэропорты представляют собой список объектов):

for airport in [a for a in airports if a.is_important]: