Абстракция списка Python
Введение | |
Синтаксис | |
Условные операторы | |
Фильтрация в отдельной функции | |
Предварительное изменение | |
Несколько источников/условий | |
Вложенные абстракции | |
Похожие статьи |
Введение
List Comprehension - Абстракция списков или списковое включение или генератор списков.
Абстракция списков или списковое включение (англ. list comprehension) в синтаксисе некоторых языков программирования — это способ компактного описания операций обработки списков.
Список можно создать и без применения абстракции списка. Например, с помощью цикла for
>>> squares = [] >>> for i in range(10): squares.append(i * i) >>> squares
Изучив синтаксис абстракции списка можно переписать это решение всего в одну строку
>>> squares = [i * i for i in range(10)] >>> squares
Результат в обоих случаях одинаковый
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Базовый синтаксис
Вместо того, чтобы создавать пустой список и добавлять каждый элемент в конец, вы просто определяете список и его содержимое одновременно, следуя этому формату:
new_list = [expression for member in iterable]
[ expr(item) for item in iterable ]
Каждая абстракция списка в Python состоит из трёх элементов (expression, member, iterable):
-
expression это может быть сам member, вызов какого-то метода или любое другое валидное выражение, которое возвращает
значение
В примере
squares = [i * i for i in range(10)]
выражение i * i это квадрат значение member.
-
member это объект или значение в списке или другом итерируемом объекте. В данном
примере значение member это i.
-
iterable может быть списком, множеством, последовательностью,
генератором
или любым другим объектом, который способен возвращать свои элементы по одному
за раз.
В данном примере iterable это range(10).
Ещё один простейший пример:
sites = ["eth1.ru", "heihei.ru", "devhops.ru", "topbicycle.ru"] print([len(site) for site in sites])
[6, 9, 10, 13]
Потому что выражение довольно гибко для вариаций, абстракция списка работает хорошо там, где
можно было бы использовать
map()
Пример с map() можете изучить
здесь
то же самое с абстракцией списка:
>>> txns = [1.09, 23.56, 57.84, 4.56, 6.78] >>> TAX_RATE = .08 >>> def get_price_with_tax(txn): ... return txn * (1 + TAX_RATE) >>> final_prices = [get_price_with_tax(i) for i in txns] >>> final_prices
[1.1772000000000002, 25.4448, 62.467200000000005, 4.9248, 7.322400000000001]
Единственная разница между этим решение и использованием map() состоит в том, что абстракция списка в Python возвращает список а map() возвращает map object.
Выгода от использования абстракции списка
Абстракции списка (List comprehensions) часто описывают как более «питоновский» способ создания списков чер loops или map().
Прежде чем соглашаться или не соглашаться с этим утверждением имеет смысл разобраться с преимуществами абстракций списков в
Python по сравнению с альтернативами.
В этой статье вы увидите несколько примеров в которых абстракция списка это лучший выбор.
Одним из основных преимуществ использования абстракции списка в Python является то, что это единый инструмент,
который вы можете использовать в самых разных ситуациях.
В дополнение к стандартному созданию списков, абстракция списка также может использоваться для сопоставления и фильтрации.
Вам не нужно использовать разный подход для каждого сценария.
Это основная причина, по которой абстракция списков считается «питоновским» подходом, поскольку
Python включает в себя простые,
мощные инструменты, которые вы можете использовать в самых разных ситуациях.
В качестве дополнительного побочного преимущества всякий раз, когда вы используете абстракцию списка в Python,
вам не нужно будет запоминать правильный порядок аргументов, как при вызове map().
Абстракция списка также более декларативна, чем циклы, что означает, что её легче читать и понимать.
Циклы требуют, чтобы вы сосредоточились на том, как создается список.
Вам нужно вручную создать пустой список, перебрать элементы и добавить каждый из них в конец списка.
Используя абстракцию списка на Python, вы можете вместо этого сосредоточиться на том, что вы хотите включить
в список, и доверять тому, что Python позаботится о том, как происходит построение списка.
Как добавить функциональности абстракциям списка
Для того, чтобы понять всю ценность, которую может обеспечить понимание списков, полезно понять диапазон их возможных функциональных возможностей.
Вы также захотите понять изменения, которые вносятся в понимание списка в Python 3.8.
Использование Conditional Logic
Ранее вы уже видели формулу создания list comprehensions:
new_list = [expression for member in iterable]
С этой формулой всё в порядке но обычно используется более сложная версия с поддержкой логических условий.
Самый распростанённый способ добавить условие (conditional logic) к абстракции списка - это добавить его в конец выражения
new_list = [expression for member in iterable (if conditional)]
В этом примере условное выражение находится прямо перед закрывающей скобкой.
Условные выражения полезны тем, что они позволяют абстракциям списков отфильтровывать нежелательные значения без вызова функции filter():
Пример с условием:
sites = ["eth1.ru", "heihei.ru", "devhops.ru", "topbicycle.ru"] it = ["eth1.ru", "devhops.ru"] print([len(site) for site in sites if site in it])
[6, 10]
Ещё один пример
>>> sentence = 'the rocket came back from mars' >>> vowels = [i for i in sentence if i in 'aeiou'] >>> vowels
['e', 'o', 'e', 'a', 'e', 'a', 'o', 'a']
В этом примере условное выражение отфильтровывает все символы, которые не являются гласными.
Ещё один пример
from math import sqrt from pprint import pprint as pp def is_prime(x): if x < 2: return False for i in range(2, int(sqrt(x)) + 1): if x % i == 0: return False return True print([x for x in range(101) if is_prime(x)])
python filtering_compreh.py
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Фильтр в отдельной функции
С помощью условий можно проверить любое валидное выражение. Если нужна более сложная фильтрация её можно вынести в отдельную функцию:
sentence = 'The rocket, who was named Ted, came back \ from Mars because he missed his friends.' def is_consonant(letter): vowels = 'aeiou' return letter.isalpha() and letter.lower() not in vowels consonants = [i for i in sentence if is_consonant(i)] print(consonants)
['T', 'h', 'r', 'c', 'k', 't', 'w', 'h', 'w', 's', 'n', 'm', 'd', \ 'T', 'd', 'c', 'm', 'b', 'c', 'k', 'f', 'r', 'm', 'M', 'r', 's', 'b', \ 'c', 's', 'h', 'm', 's', 's', 'd', 'h', 's', 'f', 'r', 'n', 'd', 's']
В этом примере создан сложный фильтр
is_consonant()
который передаётся в качестве условного выражения в абстракцию списка.
Обратите внимание, что member значение i передаётся как аргумент в функцию.
Про фильтрацию keyword arguments читайте стать *args, **kwargs
Предварительное изменение
Условное выражение можно поставить в конец для простой фильтрации, но если нужно изменить значение member вместо фильтрации условное выражение нужно поместить в начало:
new_list = [expression (if conditional) for member in iterable]
С помощью этой формулы можно использовать условные выражения для обработки различных входных значений.
Например, если у вас есть список цен, вам может быть потребуется заменить отрицательные значения на нули а положительные оставить без изменений:
>>> original_prices = [1.25, -9.45, 10.22, 3.78, -5.92, 1.16] >>> prices = [i if i > 0 else 0 for i in original_prices] >>> prices
[1.25, 0, 10.22, 3.78, 0, 1.16]
В этом примере выражение i содержит условное выражение if i > 0 else 0.
Это говорит Python вывести значение i если число положительное, но если число отрицательное вывести 0.
Возможно, более понятным будет вариант с отдельной функцией:
>>> def get_price(price): ... return price if price > 0 else 0 >>> prices = [get_price(i) for i in original_prices] >>> prices
[1.25, 0, 10.22, 3.78, 0, 1.16]
Теперь ваше условное выражение содержится внутри функции get_price(), и вы можете использовать его как часть выражения для абстракции списка.
Несколько источников/условий
Если источником данных являются списки, вложенные в другой список - можно применить for несколько раз
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] b = [x for i in a for x in i] print(b)
python list_comp.py
[1, 2, 3, 4, 5, 6, 7, 8, 9]
# Multi-input Comprehensions c = [(x, y) for x in range(5) for y in range(5)] print(c) # Without comprehension points = [] for x in range(5): for y in range(5): points.append((x, y)) print(points)
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)] [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)]
# Multiple if-clauses # Later clauses are nested inside earlier clauses values = [x / (x -y) for x in range(10) if x > 5 for y in range(10) if x - y != 0] print(values) # Without comprehension values = [] for x in range(10): if x > 5: for y in range(10): if x - y != 0: values.append(x / (x - y)) print(values)
[1.0, 1.2, 1.5, 2.0, 3.0, 6.0, -6.0, -3.0, -2.0, 1.0, 1.1666666666666667, 1.4, 1.75, 2.3333333333333335, 3.5, 7.0, -7.0, -3.5, 1.0, 1.1428571428571428, 1.3333333333333333, 1.6, 2.0, 2.6666666666666665, 4.0, 8.0, -8.0, 1.0, 1.125, 1.2857142857142858, 1.5, 1.8, 2.25, 3.0, 4.5, 9.0] [1.0, 1.2, 1.5, 2.0, 3.0, 6.0, -6.0, -3.0, -2.0, 1.0, 1.1666666666666667, 1.4, 1.75, 2.3333333333333335, 3.5, 7.0, -7.0, -3.5, 1.0, 1.1428571428571428, 1.3333333333333333, 1.6, 2.0, 2.6666666666666665, 4.0, 8.0, -8.0, 1.0, 1.125, 1.2857142857142858, 1.5, 1.8, 2.25, 3.0, 4.5, 9.0]
c = [(x, y) for x in range(5) for y in range(x)] print(c)
[(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 3)]
Вложенные абстракции
# Nested Comprehensions vals = [[y * 3 for y in range(x)] for x in range(5)] print(vals) # Without Comprehension outer = [] for x in range(5): inner = [] for y in range(x): inner.append(y * 3) outer.append(inner) print(outer)
[[], [0], [0, 3], [0, 3, 6], [0, 3, 6, 9]] [[], [0], [0, 3], [0, 3, 6], [0, 3, 6, 9]]
Встроенные коллекции | |
Списки [] | |
list comprehension: Абстракция списка | |
Python | |
if, elif, else | |
Циклы | |
Абстракция множеств и словарей |