Вирази-генератори та спискові вирази
Дві поширені операції зі значеннями, які повертає ітератор:
- Виконання певної операції для кожного елемента.
- Вибір підмножини елементів, які відповідають певній умові.
Наприклад, маючи список рядків, ви можете захотіти видалити пробіли з кінця кожного рядка або витягнути всі рядки, що містять певний підрядок.
Спискові вирази та вирази-генератори (англ. list comprehensions та generator expressions, коротка форма: "listcomps" і "genexps") — це стислий запис для таких операцій, запозичений з функціональної мови програмування Haskell (https://www.haskell.org/). Ви можете видалити всі пробіли з потоку рядків за допомогою наступного коду:
line_list = [' line 1\n', 'line 2 \n', ' \n', '']
# Вираз-генератор (generator expression) -- повертає ітератор
stripped_iter = (line.strip() for line in line_list)
print(stripped_iter)
# Списковий вираз (list comprehension) -- повертає список
stripped_list = [line.strip() for line in line_list]
print(stripped_list)
Ви можете вибрати лише певні елементи, додавши умову if
:
line_list = [' line 1\n', 'line 2 \n', ' \n', '']
# Виконуємо для усіх елементів, окрім пустих рядків ("")
stripped_list = [line.strip() for line in line_list if line != ""]
print(stripped_list)
Зі списковим виразом ви отримуєте назад список Python; stripped_list
— це список, що містить результуючі рядки, а не ітератор. Вирази-генератори повертають ітератор, який обчислює значення за необхідності, не потребуючи матеріалізувати всі значення одразу. Це означає, що спискові вирази не корисні, якщо ви працюєте з ітераторами, що повертають нескінченний потік або дуже велику кількість даних. Вирази-генератори є кращими в таких ситуаціях.
Вирази-генератори оточені круглими дужками ()
, а спискові вирази — квадратними дужками []
. Вирази-генератори мають форму:
( вираз for expr in sequence1
if condition1
for expr2 in sequence2
if condition2
for expr3 in sequence3
...
if condition3
for exprN in sequenceN
if conditionN )
Знову ж таки, для спискового виразу лише зовнішні дужки відрізняються (квадратні дужки замість круглих).
Елементи згенерованого виходу будуть послідовними значеннями виразу
. Умови if
є необов'язковими; якщо вони присутні, вираз
оцінюється і додається до результату лише тоді, коли умова
є істинною.
Вирази-генератори завжди повинні бути записані в дужках, але дужки, що сигналізують про виклик функції, також враховуються. Якщо ви хочете створити ітератор, який одразу передається функції, ви можете написати:
obj_total = sum(obj.count for obj in list_all_objects())
Умови for...in
містять послідовності, над якими треба ітерувати. Послідовності не повинні бути однієї довжини, оскільки вони ітеруються зліва направо, не паралельно. Для кожного елемента в sequence1
, sequence2
ітерується з самого початку. sequence3
потім ітерується для кожної отриманої пари елементів з sequence1
та sequence2
.
Іншими словами, спискове включення або вираз-генератор еквівалентний наступному коду Python:
for expr1 in sequence1:
if not (condition1):
continue # Пропустити цей елемент
for expr2 in sequence2:
if not (condition2):
continue # Пропустити цей елемент
...
for exprN in sequenceN:
if not (conditionN):
continue # Пропустити цей елемент
# Вивести значення
# виразу.
Це означає, що коли є кілька умов for...in
, але немає умов if
, довжина отриманого виходу буде дорівнювати добутку довжин усіх послідовностей. Якщо у вас є два списки довжиною 3, вихідний список міститиме 9 елементів:
seq1 = 'abc'
seq2 = (1, 2, 3)
[(x, y) for x in seq1 for y in seq2]
Щоб уникнути двозначності в граматиці Python, якщо вираз
створює кортеж, він повинен бути оточений дужками. Перший списковий вираз нижче є синтаксичною помилкою, тоді як другий правильний:
# Syntax error
[x, y for x in seq1 for y in seq2]
# Correct
[(x, y) for x in seq1 for y in seq2]
Текст на цій сторінці є перекладом "Functional Programming HOWTO", автор: A. M. Kuchling. Інформація про копірайт: History and License.