На этом шаге мы рассмотрим еще одну область применения генераторов.
Вам нужно выполнить функцию сокращения (т. е. sum(), min(), max()), но сначала необходимо преобразовать или отфильтровать данные.
Есть весьма элегантное решение для объединения сокращения (свертки) и преобразования данных - выражение-генератор в аргументе. Например, если вы хотите подсчитать сумму квадратов, попробуйте следующее:
nums = [1, 2, 3, 4, 5] s = sum(x * x for x in nums)
Вот еще несколько примеров:
# Определяем, есть ли файлы .py в каталоге import os files = os.listdir('dirname') if any(name.endswith('.py') for name in files): print('There be python!') else: print('Sorry, no python.')
# Выводит кортеж как CSV s = ('ACME', 50, 123.45) print(','.join(str(x) for x in s))
# Сокращение (reduction) данных по полям в структуре данных portfolio = [ {'name': 'GOOG', 'shares': 50}, {'name': 'YHOO', 'shares': 75}, {'name': 'AOL', 'shares': 20}, {'name': 'SCOX', 'shares': 65} ] min_shares = min(s['shares'] for s in portfolio)
Решение демонстрирует тонкий синтаксический аспект выражений-генераторов, связанный с передачей их как единственного аргумента в функцию: повторяющиеся скобки не нужны. Например, следующие инструкции эквивалентны:
s = sum((x * x for x in nums)) # Передаем выражение-генератор # в качестве аргумента s = sum(x * x for x in nums) # Более элегантный синтаксис
Использование аргумента-генератора часто будет более эффективным и элегантным, нежели предварительное создание временного списка. Например, если вы не используете выражение-генератор, то можете склониться к такой реализации:
nums = [1, 2, 3, 4, 5] s = sum([x * x for x in nums])
Это работает, но вводит лишний шаг и создает лишний список. Для небольшого списка из примера это не имеет значения, но если nums был огромным, вы получите крупную временную структуру данных, которая будет использована только один раз, а потом выброшена. Решение с генератором обрабатывает данные итеративно и потому намного более эффективно с точки зрения использования памяти.
Некоторые функции сокращения (свертки), такие как min() и max(), принимают аргумент key, что может оказаться полезным в ситуациях, когда вы склоняетесь к использованию генератора. Например, в этом примере вы можете попробовать альтернативный подход:
# Изначальный: возвращает 20 min_shares = min(s['shares'] for s in portfolio) # Альтернативный: возвращает {'name': 'AOL', 'shares': 20} min_shares = min(portfolio, key=lambda s: s['shares'])
На следующем шаге мы рассмотрим объединение нескольких отображений в одно.