Что такое list comprehension? Зачем оно? Какие ещё бывают?

Олег

List comprehension трудно перевести правильно на русский, потому, раз он генерирует новый список, будем называть его просто генератором списков. Это одна из самых приятных вещей в python, научившись писать которую, будешь применять её везде. Как это выглядит? Пожалуй Вы точно видели записи такого вида:

squares = [x ** 2 for x in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

это и есть генератор списка, результатом которого будет список квадратов последовательности 0..9. Что здесь происходит? Это обычный цикл for, только записан в удобочитаемом виде, в развёрнутом виде это выглядело бы так:

squares = []
for x in range(10):
  squares.append(x ** 2)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Вот тут и видна разница в этих записях — генератор списка условно можно назвать синтаксическим сахаром для цикла for, но у них разное время выполнения. Под капотом генератор списка также использует цикл for но выигрывает по скорости из-за того, то не вызывает метод append у списка (подробности здесь).

Так же как и в обычных циклах в генераторах можно применять условия:

>>> odds = [x for x in range(10) if x % 2 != 0]
# [1, 3, 5, 7, 9]

если в условии нужен else, то всё условие пишется до for:

>>> [x ** 2 if x % 2 == 0 else x ** 3 for x in range(10)]
# [0, 1, 4, 27, 16, 125, 36, 343, 64, 729]

Гораздо удобнее итерироваться по двум спискам:

first = []

for x in range(1, 5):
  for y in range(5, 1, -1):
    if x != y:
      first.append((x, y))

second = [(x, y) for x in range(1, 5) for y in range(5, 1, -1) if x != y]

>>> first == second
True

Отличный пример из документации (раскрытие списка списков), усложним его:

>>> vec = [[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]]]
>>> [digit for lst in vec for elem in lst for digit in elem]
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

Подобным образом с помощью генераторов списков мы можем создать словарь:

>>> dict([(key, value) for (key, value) in zip([1, 2, 3], ['a', 'b', 'c'])])
# {1: 'a', 2: 'b', 3: 'c'}

И тут нас ожидает приятная новость — в python есть и генераторы словарей, записываются так же, как и генераторы списков, только в фигурных скобках { ... }:

>>> {key: value for key, value in zip([1, 2, 3], ['a', 'b', 'c'])}
# {1: 'a', 2: 'b', 3: 'c'}

К слову, словарь можно создать и без генератора — dict(zip(list1, list2)).

Если мы генератор списка запишем в круглых скобках, то получим обычный генератор:

>>> gen = (x for x in range(10))
>>> gen
<generator object <genexpr> at 0x7f635076ea98>
>>> gen.__next__()
0
>>> gen.__next__()
1
.......

Официальная документация по list comprehension.

Попробуйте бесплатные уроки по Python

Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.

Переходите на страницу учебных модулей «Девмана» и выбирайте тему.