- PVSM.RU - https://www.pvsm.ru -
| Часть 1 [1] | Часть 2 [2] | Часть 3 [3] | Часть 4 |
|---|
[4]Заключительная часть моего цикла, посещенного работе с коллекциями. Данная статья самостоятельная, может изучаться и без предварительного изучения предыдущих.
Эта статья глубже и детальней предыдущих и поэтому может быть интересна не только новичкам, но и достаточно опытным Python-разработчикам.
[5]Будут рассмотрены: выражения-генераторы, генераторы списка, словаря и множества, вложенные генераторы (5 вариантов), работа с enumerate(), range().
А также: классификация и терминология, синтаксис, аналоги в виде циклов и примеры применения.
[6]Я постарался рассмотреть тонкости и нюансы, которые освещаются далеко не во всех книгах и курсах, и, в том числе, отсутствуют в уже опубликованных на HabraHabr статьях на эту тему.
1. Определения и классификация. [7]
2. Синтаксис. [8]
3. Аналоги в виде цикла for и в виде функций. [9]
4. Выражения-генераторы. [10]
5. Генерация стандартных коллекций. [11]
6. Периодичность и частичный перебор. [12]
7. Вложенные циклы и генераторы. [13]
8. Использование range(). [14]
9. Приложение 1. Дополнительные примеры. [15]
10. Приложение 2. Ссылки по теме. [16]
Сразу скажу, что существует некоторая терминологическая путаница в русских названиях того, о чем мы будем говорить.
В данной статье используются следующие обозначения:

В отдельных местах, чтобы избежать нагромождения терминов, будет использоваться термин «генератор» без дополнительных уточнений.
Для начала приведем иллюстрацию общего синтаксиса выражения-генератора.
Важно: этот синтаксис одинаков и для выражения-генератора и для всех трех типов генераторов коллекций, разница заключается, в каких скобках он будет заключен (смотрите предыдущую иллюстрацию).

list_a = [-2, -1, 0, 1, 2, 3, 4, 5] # Пусть у нас есть исходный список
list_b = [x for x in list_a] # Создадим новый список используя генератор списка
print(list_b) # [-2, -1, 0, 1, 2, 3, 4, 5]
print(list_a is list_b) # False - это разные объекты!
По сути, ничего интересного тут не произошло, мы просто получили копию списка.
Делать такие копии или просто перегонять коллекции из типа в тип с помощью генераторов особого смысла нет — это можно сделать значительно проще применив соответствующие методы или функции создания коллекций (рассматривались в первой статье цикла).
Мощь генераторов выражений заключается в том, что мы можем задавать условия для включения элемента в новую коллекцию и можем делать преобразование текущего элемента с помощью выражения или функции перед его выводом (включением в новую коллекцию).
Важно: Условие проверяется на каждой итерации, и только элементы ему удовлетворяющие идут в обработку в выражении.
Добавим в предыдущий пример условие — брать только четные элементы.
# if x % 2 == 0 - остаток от деления на 2 равен нулю - число четное
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = [x for x in list_a if x % 2 == 0]
print(list_b) # [-2, 0, 2, 4]
Мы можем использовать несколько условий, комбинируя их логическими операторами:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = [x for x in list_a if x % 2 == 0 and x > 0]
# берем те x, которые одновременно четные и больше нуля
print(list_b) # [2, 4]
Мы можем вставлять не сам текущий элемент, прошедший фильтр, а результат вычисления выражения с ним или результат его обработки функцией.
Важно: Выражение выполняется независимо на каждой итерации, обрабатывая каждый элемент индивидуально.
Например, можем посчитать квадраты значений каждого элемента
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = [x**2 for x in list_a]
print(list_b) # [4, 1, 0, 1, 4, 9, 16, 25]
Или посчитать длины строк c помощью функции len()
list_a = ['a', 'abc', 'abcde']
list_b = [len(x) for x in list_a]
print(list_b) # [1, 3, 5]
Обратите внимание: Мы можем использовать (начиная с Python 2.5) в выражении конструкцию if-else для ветвления финального выражения.
В таком случае:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = [x if x < 0 else x**2 for x in list_a]
# Если x-отрицательное - берем x, в остальных случаях - берем квадрат x
print(list_b) # [-2, -1, 0, 1, 4, 9, 16, 25]
Никто не запрещает комбинировать фильтрацию и ветвление:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = [x**3 if x < 0 else x**2 for x in list_a if x % 2 == 0]
# вначале фильтр пропускает в выражение только четные значения
# после этого ветвление в выражении для отрицательных возводит в куб, а для остальных в квадрат
print(list_b) # [-8, 0, 4, 16]
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_b = []
for x in list_a:
if x % 2 == 0:
if x < 0:
list_b.append(x ** 3)
else:
list_b.append(x ** 2)
print(list_b) # [-8, 0, 4, 16]
Не забываем, что в Python синтаксис позволяет использовать переносы строк внутри скобок. Используя эту возможность, можно сделать синтаксис генераторов выражений более легким для чтения:
numbers = range(10)
# Before
squared_odds = [n ** 2 for n in numbers if n % 2 == 0]
# After
squared_odds = [
n ** 2
for n in numbers
if n % 2 == 0
]
Как уже говорилось выше, задачи решаемые с помощью генераторов выражений можно решить и без них. Приведем другие подходы, которые могут быть использованы для решения тех же задач.
Для примера возьмем простую задачу — сделаем из списка чисел список квадратов четных чисел и решим ее с помощью трех разных подходов:
numbers = range(10)
squared_odds = [n ** 2 for n in numbers if n % 2 == 0]
print(squared_odds) # [0, 4, 8, 12, 16]
Важно: Каждый генератор выражений можно переписать в виде цикла for, но не каждый цикл for можно представить в виде такого выражения.
numbers = range(10)
squared_odds = []
for n in numbers:
if n % 2 == 0:
squared_odds.append(n ** 2)
print(squared_odds) # [0, 4, 8, 12, 16]
В целом, для очень сложных и комплексных задач, решение в виде цикла может быть понятней и проще в поддержке и доработке. Для более простых задач, синтаксис выражения-генератора будет компактней и легче в чтении.
Для начала, замечу, что выражение генераторы и генераторы коллекций — это тоже функциональный стиль, но более новый и предпочтительный.
Можно применять и более старые функциональные подходы для решения тех же задач, комбинируя map(), lambda и filter().
numbers = range(10)
squared_odds = map(lambda n: n * 2, filter(lambda n: n % 2 == 0, numbers))
print(squared_odds) # <map object at 0x7f661e5dba20>
print(list(squared_odds)) # [0, 4, 8, 12, 16]
Несмотря на то, что подобный пример вполне рабочий, читается он тяжело и использование синтаксиса генераторов выражений будет более предпочительным и понятным.
Выражения-генераторы (generator expressions) доступны, начиная с Python 2.4.
Основное их отличие от генераторов коллекций в том, что они выдают элемент по-одному, не загружая в память сразу всю коллекцию.
Пример выражения-генератора:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
my_gen = (i for i in list_a) # выражение-генератор
print(next(my_gen)) # -2 - получаем очередной элемент генератора
print(next(my_gen)) # -1 - получаем очередной элемент генератора
# my_gen = i for i in list_a # SyntaxError: invalid syntax
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
my_sum = sum(i for i in list_a)
# my_sum = sum((i for i in list_a)) # так тоже можно
print(my_sum) # 12
# my_len = len(i for i in list_a) # TypeError: object of type 'generator' has no len()
print(my_gen) # <generator object <genexpr> at 0x7f162db32af0>
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
my_gen = (i for i in list_a)
print(sum(my_gen)) # 12
print(sum(my_gen)) # 0
import itertools
inf_gen = (x for x in itertools.count()) # бесконечный генератор от 0 to бесконечности!
Будьте осторожны в работе с такими генераторами, так как при не правильном использовании «эффект» будет как от бесконечного цикла.
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
my_gen = (i for i in list_a)
my_gen_sliced = my_gen[1:3]
# TypeError: 'generator' object is not subscriptable
Создание коллекций из выражения-генератора с помощью функций list(), tuple(), set(), frozenset()
Примечание: Так можно создать и неизменное множество и кортеж, так как неизменными они станет уже после генерации.
Внимание: Для словаря и строки такие способы не работают!
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
my_gen = (i for i in list_a) # выражение-генератор
my_list = list(my_gen)
print(my_list) # [-2, -1, 0, 1, 2, 3, 4, 5]
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
my_list = list(i for i in list_a)
print(my_list) # [-2, -1, 0, 1, 2, 3, 4, 5]
# кортеж
my_tuple = tuple(i for i in list_a)
print(my_tuple) # (-2, -1, 0, 1, 2, 3, 4, 5)
# множество
my_set = set(i for i in list_a)
print(my_set) # {0, 1, 2, 3, 4, 5, -1, -2}
# неизменное множество
my_frozenset = frozenset(i for i in list_a)
print(my_frozenset) # frozenset({0, 1, 2, 3, 4, 5, -1, -2})
В отличии от выражения-генератора, которое выдает значение по-одному, не загружая всю коллекцию в память, при использовании генераторов коллекций, коллекция генерируется сразу целиком.
Соответственно, вместо особенности выражений-генераторов перечисленных выше, такая коллекция будет обладать всеми стандартными свойствами характерными для коллекции данного типа.
Обратите внимание, что для генерации множества и словаря используются одинаковые скобки, разница в том, что у словаря указывается двойной элемент ключ: значение.
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
my_list = [i for i in list_a]
print(my_list) # [-2, -1, 0, 1, 2, 3, 4, 5]
Не пишите круглые скобки в квадратных!
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
my_list = [(i for i in list_a)]
print(my_list) # [<generator object <genexpr> at 0x7fb81103bf68>]
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
my_set= {i for i in list_a}
print(my_set) # {0, 1, 2, 3, 4, 5, -1, -2} - порядок случаен
dict_abc = {'a': 1, 'b': 2, 'c': 3, 'd': 3}
dict_123 = {v: k for k, v in dict_abc.items()}
print(dict_123) # {1: 'a', 2: 'b', 3: 'd'}
# Обратите внимание, мы потеряли "с"! Так как значения были одинаковы,
# то когда они стали ключами, только последнее значение сохранилось.
Словарь из списка:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
dict_a = {x: x**2 for x in list_a}
print(dict_a) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, -2: 4, -1: 1, 5: 25}
Важно! Такой синтаксис создания словаря работает только в фигурных скобках, выражение-генератор так создать нельзя!
# dict_gen = (x: x**2 for x in list_a) # SyntaxError: invalid syntax
# dict_a = dict(x: x**2 for x in list_a) # SyntaxError: invalid syntax
UPD от longclaps [17]:
# dict_a = dict(x: x**2 for x in list_a) # SyntaxError: invalid syntax
dict_a = dict((x, x ** 2) for x in list_a) # Корректный вариант синтаксиса
Для создания строки вместо синтаксиса выражений-генераторов используется метод строки .join(), которому в качестве аргументов можно передать выражение генератор.
Обратите внимание: элементы коллекции для объединения в строку должны быть строками!
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
# используем генератор прямо в .join() одновременно приводя элементы к строковому типу
my_str = ''.join(str(x) for x in list_a)
print(my_str) # -2-1012345
Иногда в условиях задачи в условии-фильтре нужна не проверка значения текущего элемента, а проверка на определенную периодичность, то есть, например, нужно брать каждый третий элемент.
Для подобных задач можно использовать функцию enumerate(), задающую счетчик при обходе итератора в цикле:
for i, x in enumerate(iterable)
здесь x — текущий элемент i — его порядковый номер, начиная с нуля
Проиллюстрируем работу с индексами:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_d = [(i, x) for i, x in enumerate(list_a)]
print(list_d) # [(0, -2), (1, -1), (2, 0), (3, 1), (4, 2), (5, 3), (6, 4), (7, 5)]
Теперь попробуем решить реальную задачу — выберем в генераторе списка каждый третий элемент из исходного списка:
list_a = [-2, -1, 0, 1, 2, 3, 4, 5]
list_e = [x for i, x in enumerate(list_a, 1) if i % 3 == 0]
print(list_e) # [0, 3]
first_ten_even = [(i, x) for i, x in enumerate(range(10)) if x % 2 == 0]
print(first_ten_even) # [(0, 0), (2, 2), (4, 4), (6, 6), (8, 8)]
Иногда бывает задача из очень большой коллекции или даже бесконечного генератора получить выборку первых нескольких элементов, удовлетворяющих условию.
Если мы используем обычное генераторное выражение с условием ограничением по enumerate() индексу или срез полученной результирующей коллекции, то нам в любом случае придется пройти всю огромную коллекцию и потратить на это уйму компьютерных ресурсов.
Выходом может быть использование функции islice() из пакета itertools.
import itertools
first_ten = (itertools.islice((x for x in range(1000000000) if x % 2 == 0), 10))
print(list(first_ten)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
import time
import itertools
# На генераторе с малым количеством элементов
start_time = time.time()
first_ten = (itertools.islice((x for x in range(100) if x % 2 == 0), 10))
print(list(first_ten)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
elapsed_time = time.time() - start_time
print(elapsed_time) # 3.409385681152344e-05
# На генераторе с огромным количеством элементов
start_time = time.time()
first_ten = (itertools.islice((x for x in range(100000000) if x % 2 == 0), 10))
print(list(first_ten)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
elapsed_time = time.time() - start_time
print(elapsed_time) # 1.1205673217773438e-05
# То есть максимальное количество элементов в генераторе range() мы увеличили на 6 порядков,
# а время исполнения осталось того же порядка
Рассмотрим более комплексные варианты, когда у нас циклы или сами выражения-генераторы являются вложенными. Тут возможны несколько вариантов, со своими особенностями и сферой применения, чтобы не возникало путаницы, рассмотрим их по-отдельности, а после приведем общую схему.
В результате генерации получаем одномерную структуру.
Важно! При работае с вложенными циклами внутри генератора выражений порядок следования инструкций for in будет такой же (слева-направо), как и в аналогичном решении без генератора, только на циклах (сверху-вниз)! Тоже справедливо и при более глубоких уровнях вложенности.
Общий синтаксис: [expression for x in iter1 for y in iter2]
Применение: генерируем одномерную структуру, используя данные из двух итераторов.
Например, создадим словарь, используя кортежи координат как ключи, заполнив для начала его значения нулями.
rows = 1, 2, 3
cols = 'a', 'b'
my_dict = {(col, row): 0 for row in rows for col in cols}
print(my_dict) # {('a', 1): 0, ('b', 2): 0, ('b', 3): 0, ('b', 1): 0, ('a', 3): 0, ('a', 2): 0}
my_dict['b', 2] = 10 # задаем значение по координатному ключу-кортежу
print(my_dict['b', 2]) # 10 - получаем значение по координатному ключу-кортежу
Тоже можно сделать и с дополнительными условиями-фильтрами в каждом цикле:
rows = 1, 2, 3, -4, -5
cols = 'a', 'b', 'abc'
# Для наглядности разнесем на несколько строк
my_dict = {
(col, row): 0 # каждый элемент состоит из ключа-кортежа и нулевого знаечния
for row in rows if row > 0 # Только положительные значения
for col in cols if len(col) == 1 # Только односимвольные
}
print(my_dict) # {('a', 1): 0, ('b', 2): 0, ('b', 3): 0, ('b', 1): 0, ('a', 3): 0, ('a', 2): 0}
rows = 1, 2, 3, -4, -5
cols = 'a', 'b', 'abc'
my_dict = {}
for row in rows:
if row > 0:
for col in cols:
if len(col) == 1:
my_dict[col, row] = 0
print(my_dict) # {('a', 1): 0, ('b', 2): 0, ('b', 3): 0, ('b', 1): 0, ('a', 3): 0, ('a', 2): 0}
Общий синтаксис: [expression for x in iterator for y in x].
Применение: Стандартный подход, когда нам надо обходить двумерную структуру данных, превращая ее в «плоскую» одномерную. В данном случае, мы во внешнем цикле проходим по строкам, а во внутреннем по элементам каждой строки нашей двумерной структуры.
Допустим у нас есть двумерная матрица — список списков.
И мы желаем преобразовать ее в плоский одномерный список.
matrix = [[0, 1, 2, 3],
[10, 11, 12, 13],
[20, 21, 22, 23]]
# Решение с помощью генератора списка:
flattened = [n for row in matrix for n in row]
print(flattened) # [0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23]
flattened = []
for row in matrix:
for n in row:
flattened.append(n)
print(flattened)
Вложенными могут быть не только циклы for внутри выражения-генератора, но и сами генераторы.
Такой подход применяется когда нам надо строить двумерную структуру.
Важно!: В отличии от примеров выше с вложенными циклами, для вложенных генераторов, вначале обрабатывается внешний генератор, потом внутренний, то есть порядок идет справа-налево.
Ниже рассмотрим два варианта подобного использования.
Общий синтаксис: [[expression for y in iter2] for x in iter1]
Применение: генерируем двумерную структуру, используя данные из двух одномерных итераторов.
Для примера создадим матрицу из 5 столбцов и 3 строк и заполним ее нулями
w, h = 5, 3 # зададим ширину и высотку матрицы
matrix = [[0 for x in range(w)] for y in range(h)]
print(matrix) # [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
matrix = []
for y in range(h):
new_row = []
for x in range(w):
new_row.append(0)
matrix.append(new_row)
print(matrix) # [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
# теперь можно добавлять значения по координатам (координаты - индексы в списке списков)
matrix[0][0] = 1
matrix[1][3] = 3
print(matrix) # [[1, 0, 0, 0, 0], [0, 0, 0, 3, 0], [0, 0, 0, 0, 0]]
# Получаем значение по произвольным координатам
x, y = 1, 3
print(matrix[x][y]) # 3
Общий синтаксис: [[expression for y in x] for x in iterator]
Применение: Обходим двумерную структуру данных, сохраняя результат в другую двумерную структуру.
Возьмем матрицу
matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
Возведем каждый элемент матрицы в квадрат
squared = [[cell**2 for cell in row] for row in matrix]
print(squared) # [[1, 4, 9, 16], [25, 36, 49, 64], [81, 100, 121, 144]]
squared = []
for row in matrix:
new_row = []
for cell in row:
new_row.append(cell**2)
squared.append(new_row)
print(squared) # [[1, 4, 9, 16], [25, 36, 49, 64], [81, 100, 121, 144]]
Обобщим все вышеперечисленные варианты в одной схеме (полный размер по клику):
[6]
Примечание: Лично я не вижу преимуществ в применении такого комбинирования генераторов, так как это ведет к ухудшению читаемости кода без добавления особых преимуществ.
Но, поскольку такой синтаксис допустим, проиллюстрирую и такую возможность.
Допустим у нас есть два таких генератора списков:
list_a = [x for x in range(-2, 4)] # Так сделано для дальнейшего примера синтаксиса,
# конечно в подобной задаче досточно только range(-2, 4)
list_b = [x**2 for x in list_a]
Тоже самое можно записать и в одно выражение, подставив вместо list_a его генератор списка:
list_c = [x**2 for x in [x for x in range(-2, 4)]]
print(list_c) # [4, 1, 0, 1, 4, 9]
Говоря о способах генерации коллекций, нельзя обойти вниманием простую и очень удобную функцию range(), которая предназначена для создания арифметических последовательностей.
Примеры использования:
print(list(range(5))) # [0, 1, 2, 3, 4]
print(list(range(-2, 5))) # [-2, -1, 0, 1, 2, 3, 4]
print(list(range(5, -2, -2))) # [5, 3, 1, -1]
import itertools
l1 = [1,2,3]
l2 = [10,20,30]
result = [l*2 for l in itertools.chain(l1, l2)]
print(result) # [2, 4, 6, 20, 40, 60]
(Преобразование матрицы, когда строки меняются местами со столбцами).
Возьмем матрицу.
matrix = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]]
Сделаем ее транспозицию с помощью генератора выражений
transposed = [[row[i] for row in matrix] for i in range(4)]
print(transposed) # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
transposed = []
for i in range(4):
new_row = []
for row in matrix:
new_row.append(row[i])
transposed.append(new_row)
print(transposed) # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
transposed = list(map(list, zip(*matrix)))
print(transposed) # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
# Формируем список дней от 1 до 31 с которым будем работать
days = [d for d in range(1, 32)]
# Делим список дней на недели
weeks = [days[i:i+7] for i in range(0, len(days), 7)]
print(weeks) # [[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14], [15, 16, 17, 18, 19, 20, 21], [22, 23, 24, 25, 26, 27, 28], [29, 30, 31]]
# Выбираем в каждой неделе только первые 5 рабочих дней, отбрасывая остальные
work_weeks = [week[0:5] for week in weeks]
print(work_weeks) # [[1, 2, 3, 4, 5], [8, 9, 10, 11, 12], [15, 16, 17, 18, 19], [22, 23, 24, 25, 26], [29, 30, 31]]
# Если нужно одним списком дней - можно объединить
wdays = [item for sublist in work_weeks for item in sublist]
print(wdays) # [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31]
# Формируем список дней от 1 до 31 с которым будем работать
days = [d for d in range(1, 32)]
wdays6 = [wd for (i, wd) in enumerate(days, 1) if i % 7 != 0] # Удаляем каждый 7-й день
# Удаляем каждый 6 день в оставшихся после первого удаления:
wdays5 = [wd for (i, wd) in enumerate(wdays6, 1) if i % 6 != 0]
print(wdays5)
# [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31]
# Обратите внимание, что просто объединить два условия в одном if не получится,
# как минимум потому, что 12-й день делится на 6, но не выпадает на последний 2 дня недели!
squared_odds = [n ** 2 # SELECT
for n in numbers # FROM
if n % 2 == 0] # WHERE
| Часть 1 [1] | Часть 2 [2] | Часть 3 [3] | Часть 4 |
|---|
Автор: DaneSoul
Источник [22]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/239486
Ссылки в тексте:
[1] Часть 1: https://habrahabr.ru/post/319164/
[2] Часть 2: https://habrahabr.ru/post/319200/
[3] Часть 3: https://habrahabr.ru/post/319876/
[4] Image: https://habrastorage.org/files/104/b44/afc/104b44afce044fb88d04492dd012d078.png
[5] Image: https://habrastorage.org/files/688/052/4d1/6880524d12ff4f689c0a84d1302c5715.png
[6] Image: https://habrastorage.org/files/d15/679/28e/d1567928e55649d59fb95f337ef0387f.png
[7] Определения и классификация.: #1
[8] Синтаксис.: #2
[9] Аналоги в виде цикла for и в виде функций.: #3
[10] Выражения-генераторы.: #4
[11] Генерация стандартных коллекций.: #5
[12] Периодичность и частичный перебор.: #6
[13] Вложенные циклы и генераторы.: #7
[14] Использование range().: #8
[15] Приложение 1. Дополнительные примеры.: #9
[16] Приложение 2. Ссылки по теме.: #10
[17] longclaps: https://habrahabr.ru/users/longclaps/
[18] детальным объяснением что такое генераторы и итераторы: http://nvie.com/posts/iterators-vs-generators/
[19] аналогии между генераторными выражениями и работой с SQL и таблицами Excel: http://blog.lerner.co.il/want-to-understand-pythons-comprehensions-think-like-an-accountant/
[20] синтаксис генераторных выражений: http://treyhunner.com/2015/12/python-list-comprehensions-now-in-color/
[21] вложенных генераторных выражений: http://blog.lerner.co.il/understanding-nested-list-comprehensions-in-python/
[22] Источник: https://habrahabr.ru/post/320288/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.