article banner

Генераторні списки на Python

Це фрагмент книги Python з нуля, яка допоможе вам навчитися програмуванню з нуля. Ви можете знайти його на Allegro, Empik та в інтернет-книгарнях.

Цикл for призначений не лише для ітерації range. Навіть навпаки. Набагато більш поширеним є його використання для ітерації по списку або таплу.

names = ["Аля", "Бася", "Целіна"]
for name in names:
    print(name)

# Виведе:
# Аля
# Бася
# Целіна

Однак, коли ми вже згадали ітерацію по списках, варто вивчити дуже корисний функціонал — генераторні списки.

Генераторні списки

Менш відомим, проте дуже корисним функціоналом мови Python є генераторні списки 1. Вони дозволяють створювати нові списки на основі наявних списків або діапазонів із певними змінами.

Погляньмо, як працює генератор списків. Він визначає, що має бути в новому списку. Приклад генератора — це x * 10 for x in numbers, тобто, ми хочемо х * 10 для всіх x з numbers. Такий генератор повертатиме послідовні елементи з numbers, помножені на 10. Якщо взяти його в квадратні дужки, ми отримаємо список із цими значеннями.

numbers = [x + 1 for x in range(5)]
print(numbers)  # [1, 2, 3, 4, 5]
numbers = [x * 10 for x in range(5)]
print(numbers)  # [0, 10, 20, 30, 40]

Аналогічно ми можемо редагувати рядки. Наприклад, можна використати метод upper, щоб імена в новому списку починалися з великої літери.

names = ["Ада", "Бася", "Целіна"]
names_upper = [name.upper() for name in names]
print(names_upper)  # ['АДА', 'БАСЯ', 'ЦЕЛІНА']

Зауваж, що ми можемо отримати той самий ефект за допомогою циклу for та нового списку.

new_list = [transformation(x) for x in old_list]

# Можна отримати таким чином:
new_list = []
for x in old_list:
    new_list.append(transformation(x))

На практиці ми часто використовуємо цей функціонал для перетворення списку об’єктів у новий список. Наприклад, якщо б у нас був список лікарів, але нас цікавили б лише їхні імена, ми могли б використати генератор списків, щоб їх отримати.

doctor_names = [doctor.name for doctor in doctors]

Генераторні списки з заданою умовою

Інший варіант — додавання умови, яка має бути виконана, щоб елементи було включено до нового списку. Цю умову додаємо після слова if в кінці генератора. В умові ми можемо використовувати назву змінної, визначену між for та in. Наприклад, якщо зі списку імен ми хочемо вибрати лише ті, які починаються на літеру "М", то можемо зробити це наступним чином:

names = ["Йола", "Марцін", "Каміль", "Майя", "Стефан"]
m_names = [name for name in names if name[0] == "M"]
print(m_names)  # ['Марцін', 'Майя']

Додавання умови не заважає нам застосувати перетворення, про які йшлося раніше.

names = ["Йола", "Марцін", "Каміль", "Майя", "Стефан"]
m_names = [name.upper() for name in names
           if name[0] == "M"]
print(m_names)  # ['МАРЦІН', 'МАЙЯ']

Ми могли б отримати аналогічний результат, використовуючи цикл for і новий список. Втім тоді довелося б додати умову if.

new_list = [transformation(x) for x in old_list
            if condition(x)]

# Можна також отримати таким чином:
new_list = []
for x in old_list:
    if condition(x):
        new_list.append(transformation(x))

Створення таплів за допомогою генераторів

Варто додати, що за допомогою генераторів можна обробляти і тапли. Тут генератор має перейти до конструктора tuple. Усі інші функції залишаються незмінними.

names = ("Йола", "Марцін", "Каміль", "Майя", "Стефан")
names = tuple(name for name in names if name[0] == "M")
print(names)  # ('Марцін', 'Майя')
print(type(names))  # <class 'tuple'>

Вправа: Ітерація та генератори списків

Для наступної змінної names:

  • склади список, у якому всі імена починатимуться з великої літери (пригадай методи класу str);
  • створи кортеж, який містить тільки жіночі імена, які починаються з великої літери (для потреб цієї вправи, жіночі імена — це ті, які закінчуються на "я");
  • підрахуй загальну довжину всіх цих імен (довжина рядка перевіряється функцією len; пам’ятай, що Ти можеш використати цикл і додавати в ньому значення до змінної).
names = ["міхал", "неля", "оля", "пшемек"]

Відповіді в кінці книги.

1:

"Генераторні списки" — наближений переклад з англійської поняття "list comprehension". У деяких книгах цей термін перекладається як "спискові вирази", але це не зовсім вірно, оскільки "списковий вираз" включає значно більше (у тому числі, наприклад, створення списків за допомогою квадратних дужок). Інші джерела використовують термін "відтворення списків", який має включати значно менше (виключно мапування).