Курс по Python: https://stepik.org/course/100707
Мы продолжаем курс по языку
программирования Python. На этом занятии мы с вами познакомимся
с еще одной довольно полезной и популярной конструкцией – генератором списков.
По-английски это записывается как:
List
comprehension
Для лучшего
понимания, давайте я начну сразу с конкретного примера. Предположим, мы хотели
бы сформировать список из квадратов целых чисел от 0 до N. Используя наши
текущие знания, очевидно, это можно было бы сделать, следующим образом:
N = 6
a = [0] * N
for i in range(N):
a[i] = i ** 2
print(a)
Но это не лучший
вариант. Все то же самое можно реализовать буквально в одну строчку:
a = [x ** 2 for x in range(N)]
И, кроме того,
этот вариант будет работать быстрее предыдущей программы, т.к. Python оптимизирует
работу таких конструкций.
Давайте теперь
разберемся в этом синтаксисе. Вначале мы указываем, что будем делать с
переменной x. Казалось бы,
переменная нигде не задана, а мы уже говорим что с ней делать. Да, это так, это
такой элемент синтаксиса list comprehensions. Далее, через пробел
мы записываем цикл for и уже там указываем эту переменную x и говорим как
она будет меняться. То есть, эта временная переменная x существует
только внутри списка и пропадает после его создания.
Такой подход и
называется генератором списков. Вначале указываем, как формируются значения
списка, а затем, описываем изменение параметра x через ключевое
слово for. Причем, здесь можно
указывать только его. К примеру, ключевое слово while прописывать
нельзя.
Итак, для
генерации списков следует придерживаться следующего синтаксиса (определения):
[<способ
формирования значения> for <переменная> in <итерируемый
объект>]
В самом простом
варианте мы можем сформировать список и так:
a = [1 for x in range(N)]
Хотя, в таких
случаях, когда все значения одинаковы, обычно, используют оператор *:
Но, в отличие от
простого дублирования с помощью List comprehension можно формировать более
сложные последовательности, например, состоящих из остатков от деления на 4:
a = [x % 4 for x in range(N)]
То есть, мы
можем использовать любые доступные нам операторы для формирования текущего
значения. Если, например, взять оператор определения четного и нечетного
значений:
a = [x % 2 == 0 for x in range(N)]
то получим
список из булевых величин True и False. Или же
сформировать значения линейной функции:
a = [0.5*x+1 for x in range(N)]
И так далее. Кроме
того, мы здесь можем вызывать и функции. Пусть в программе пользователь вводит
несколько целых чисел через пробел:
d_inp = input("Целые числа через пробел: ")
Тогда с помощью
генератора списков мы легко можем преобразовать их в набор чисел:
a = [int(d) for d in d_inp.split()]
Здесь
конструкция d_inp.split() возвращает
список строк из чисел, а функция int(d)
преобразовывает каждую строку в целое число. Если убрать функцию int() и записать
просто d:
a = [d for d in d_inp.split()]
то у нас
получится уже список из строк, то есть, функция int() действительно
делает нужное нам преобразование.
Работа этой
реализации очень похожа на функцию map(), которую мы с вами
использовали в подобных задачах:
d_inp = list(map(int, input("Целые числа через пробел: ").split()))
(О функции map() подробнее мы
еще будем говорить).
Вообще, в
генераторе списков можно использовать любые итерируемые объекты, в том числе и
строки. Например, вполне допустима такая реализация:
a = [d for d in "python"]
получим список
из отдельных символов. Или, можно каждый символ превратить в его код:
a = [ord(d) for d in "python"]
Имеем список из
соответствующих кодов. Если же взять список из слов:
t = ["Я", "б", "Python", "выучил", "только", "за", "то", "что", "есть", "он", "на", "этом", "канале"]
то генератор
списка:
сформирует точно
такой же список. То есть, строки здесь воспринимаются уже как отдельные
элементы и d ссылается на
каждую из них по порядку. Я добавлю функцию len() для
определения длины строк:
и теперь мы
имеем список из длин.
Условия в генераторах списков
В генераторах
дополнительно можно прописывать условия. Например, выберем все числа меньше
нуля:
a = [x for x in range(-5, 5) if x < 0]
Мы здесь после
оператора for записали
необязательный оператор if. В результате, в список будут попадать
только отрицательные значения x. Или, можно сделать проверку на
нечетность:
a = [x for x in range(-5, 5) if x % 2 != 0]
Получаем только
нечетные числа из диапазона [-5; 5). Также можно прописывать составные условия,
например:
a = [x for x in range(-6, 7) if x % 2 == 0 and x % 3 == 0]
Выберем все
числа, которые кратны 2 и 3 одновременно. Или, такой пример, выберем из списка
городов только те, длина которых меньше семи:
cities = ["Москва", "Тверь", "Рязань", "Ярославль", "Владимир"]
a = [city for city in cities if len(city) < 7]
Видите, как
легко и просто можно реализовать такую задачу с помощью List comprehension.
Ну и последнее,
что я хочу отметить на этом занятии – это возможность использования тернарного
условного оператора внутри генераторов списков. Так как первым элементом мы
можем прописывать любые конструкции языка Python, то кто нам
мешает сделать следующее. Пусть имеется список чисел:
d = [4, 3, -5, 0, 2, 11, 122, -8, 9]
и мы хотим
преобразовать его в последовательность со словами «четное» и «нечетное».
Сделать это можно как раз с помощью тернарного условного оператора:
a = ["четное" if x % 2 == 0 else "нечетное" for x in d]
Обратите еще раз
внимание, что этот оператор не является какой-то особой частью синтаксиса
генератора списка. Мы здесь всего лишь используем его как обычный оператор
языка Python. Это такой же
оператор как сложение, умножение и другие:
которые мы также
можем использовать при формировании списков.
Полученная
запись генератора списка с тернарным оператором получилась не очень читаемой.
Это можно исправить, если записать все в отдельных строчках:
a = ["четное" if x % 2 == 0 else "нечетное"
for x in d
if x > 0
]
Кстати, здесь
можно добавить еще и условие.
На этом мы
завершим первое знакомство с генераторами списков. Для закрепления материала
обязательно пройдите практические задания, после чего переходите к следующему
уроку, где мы продолжим знакомиться с этой темой.
Курс по Python: https://stepik.org/course/100707