Метка: starmap

Генераторные выражения

Edison dynamo - КДПВ

Мы говорили про map и itertools.starmap, но я тут подумал… Зачем они, если есть замечательные генераторные выражения:

  • Они умеют делать: генераторы, списки list, словари dict и множества set.
  • Поддерживают вложенные циклы для обработки многомерных данных
  • Умеют фильтровать данные, как filter
  • Обладают лаконичным и понятным синтаксисом

По-английски они называются в зависимости от типа данных на выходе: generator expressions и list/dictionary/set comprehensions.

Если нам нужен генератор, то ставим круглые скобки. Если нужен сразу список – квадратные. Если нужен словарь или множество – фигурные. А внутри цикл for/in. Наш «прибавлятор» единицы стал короче и без лямбд:

>>> list(map(lambda x: x + 1, [1, 2, 3, 4]))
[2, 3, 4, 5]

>>> [x + 1 for x in [1, 2, 3, 4]]
[2, 3, 4, 5]

Пример на замену starmap не то чтобы сильно короче, но значительно понятнее, потому что виден фактический вызов pow и разумные имена переменных:

>>> from itertools import starmap
>>> list(starmap(pow, [(2, 4), (3, 2), (5, 2)]))
[16, 9, 25]

>>> [pow(base, exp) for base, exp in [(2, 4), (3, 2), (5, 2)]]
[16, 9, 25]

Если нужно множество (коллекция без повторов), то все то же самое, но скобки фигурные. Пример: все уникальные буквы слова:

>>> {r for r in 'BANANA'}
{'N', 'B', 'A'}

Если нужен словарь, то скобки также фигурные, но генерируем парами «ключ: значение». Пример: ключ – строка, значение – строка задом наперед:

>>> {key: key[::-1] for key in ["Mama", "Papa"]}
{'Mama': 'amaM', 'Papa': 'apaP'}

Наконец, если нужен генератор, то скобки круглые. Генератор вычисляет и выдает значения лениво (по одному, когда они требуются):

>>> g = (x ** 2 for x in [1, 2, 3, 4])
>>> next(g)
1
>>> print(*g)
4 9 16

Если функция принимает ровно 1 аргумент, то передавая в нее генератор можно опустить лишние круглые скобки:

>>> sum(x ** 2 for x in [1, 2, 3, 4])
30

Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈 

starmap – это не звездная карта!

Встроенная функция map принимает функцию и итерируемый объект, а возвращает тоже итератор, применяя ту функцию к каждому элементу исходного итератора. А, чтобы получить список, мы извлекаем из итератора все значения, приведя его к списку функцией list. Пример map: прибавлятор единички ко всем элементам массива:

>> list(map(lambda x: x + 1, [1, 2, 3, 4]))
[2, 3, 4, 5]

Что делать, если нужно применить функцию, которая принимает большее количество аргументов? Например, возведение в степень pow принимает основание и показатель:

>>> pow(2, 4)
16

Как и требуют, мы даем в map функцию с одним аргументом, но каждый элемент t – кортеж из двух элементов, мы распаковываем его в аргументы pow звездочкой:

>>> list(map(lambda t: pow(*t), [(2, 4), (3, 2), (5, 2)]))
[16, 9, 25]

Если вы не знали: pow(*t) то же самое, что и pow(t[0], t[1]), если в t два элемента.

К счастью, не обязательно делать этот хак с лямбдой, потому что в модуле itertools есть функция starmap, которая как раз звездочкой распаковывает каждый элемент исходного итератора в аргументы функции:

>>> from itertools import starmap
>>> list(starmap(pow, [(2, 4), (3, 2), (5, 2)]))
[16, 9, 25]
Схема работы map и starmap показывает как передаются аргументы

🐉 Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈