В языке Python заложено много полезных инструментов, способных значительно упростить жизнь разработчику, если о них знать и уметь использовать. Мы рассмотрим четыре функции, которые помогут нам при работе с циклом for, а в некоторых случаях позволят вообще отказаться от него!
О операторах ветвления и циклах написано в уроке “Python. Урок 5. Условные операторы и циклы”.
В статье рассмотрим следующие функции:
Функция range
Функция range() создает объект, который внутри себя содержит итератор, выдающий элементы из диапазона, определяемого аргументами функции.
Создадим объект range.
>>> r = range(3)
Получим его итератор.
>>> ri = iter(r)
Используя next(), извлечем из него все элементы.
>>> next(ri) 0 >>> next(ri) 1 >>> next(ri) 2 >>> next(ri) Traceback (most recent call last): File "<pyshell#18>", line 1, in <module> next(ri) StopIteration
Через параметры функции range можно задать диапазон и шаг. Создадим range, генерирующий числа от 1 до 10 с шагом 3.
>>> ri2 = iter(range(1,10,3)) >>> next(ri2) 1 >>> next(ri2) 4 >>> next(ri2) 7 >>> next(ri2) Traceback (most recent call last): File "<pyshell#25>", line 1, in <module> next(ri2) StopIteration
Объект range идеально подходит для использования в цикле for. Работа цикла for организована следующим образом:
- получаем итератор у объекта, который предоставляет данные;
- используя функцию next(), извлекаем элементы на каждой итерации цикла;
- если произошел выброс исключения StopIteration, то выходим из цикла.
Пример: выведем список целых чисел от 0 до 2 на экран.
>>> for i in range(3): print(i) 0 1 2
Список чисел от 1 до 10 с шагом 2.
>>> for i in range(1, 10, 2): print(i) 1 3 5 7 9
Range можно использовать в List Comprehensions.
>>> [i for i in range(3)] [0, 1, 2]
Функция range() – мощный инструмент, позволяющий получать последовательности целых чисел в заданном диапазоне с определенным шагом, с доступом через итератор.
Функция enumerate
Функция enumerate() конструирует генератор по переданной в нее (через аргумент) объект. Она предоставляет кортежи, состоящие из двух элементов, первый из которых – индекс, а второй – значение, извлекаемое из объекта.
Рассмотрим простой пример: найти в строке первое вхождение символа ‘o’ и вывести номер его позиции. Эта задача может быть решена так.
>>> msg = "hello!" >>> i = 0 >>> for sym in msg: if sym == 'o': print("index = ", i) break i += 1 index = 4
В этой программе нам пришлось заводить дополнительную переменную i, значение которой на каждой итерации цикла мы увеличивали на единицу. Это не очень удобно! Использование функции enumerate() позволит упростить решение.
>>> msg = "hello!" >>> for tp in enumerate(msg): if 'o' in tp: print("index = ", tp[0]) index = 4
В процессе работы цикла for из объекта, созданного функцией enumerate(), будут последовательно извлекаться следующие кортежи:
(0, ‘h’) (1, ‘e’) (2, ‘l’) (3, ‘l’) (4, ‘o’)
После извлечения кортежа (4, ‘o’), на экран выведется соответствующее сообщение и цикл завершится. Выведем все кортежи, получаемые из строки “hello!” с помощью функции enumerate().
>>> for tp in enumerate(msg): print(tp) (0, 'h') (1, 'e') (2, 'l') (3, 'l') (4, 'o') (5, '!')
Функция enumerate() позволяет получить индексы элементов объекта при обходе его в цикле for без введения дополнительных переменных.
Функция map
Функция map() предоставляет возможность применить указанную функцию к каждому элементу объекта. В результате получим список из модифицированных элементов исходного объекта.
Решим задачу возведения в квадрат всех элементов списка с использованием цикла for.
>>> numbers = [1, 2, 3, 4, 5] >>> sq_nums = [] >>> for num in numbers: sq_nums.append(num**2) >>> sq_nums [1, 4, 9, 16, 25]
Эту задачу можно также решить с использованием List Comprehensions.
>>> sq_nums = [num**2 for num in numbers] >>> sq_nums [1, 4, 9, 16, 25]
Точно такой же результат получим, если воспользуемся функций map().
>>> sq_nums = list(map(lambda x: x**2, numbers)) >>> sq_nums [1, 4, 9, 16, 25]
На первый взгляд такой подход может показаться сложнее предыдущего, но вся его мощь заключается в первом аргументе – функции, которая используется для модификации значений элементов объекта. Это может быть как lambda-функция, как в нашем примере, так функция, созданная с использованием ключевого слова def.
Результат работы функции map() можно использовать в цикле for.
>>> msg = "simple" >>> for sym in map(lambda x: x+'-', msg): print(sym, end='') s-i-m-p-l-e-
Используйте map(), если вам необходимо обработать элементы объекта, используя определенную функцию .
Функция zip
Функция zip() позволяет в одном цикле for производить параллельную обработку данных. Это очень мощный инструмент! Zip принимает в качестве аргументов объекты, элементы которых будут объединены в кортежи, полученную структуру можно превратить в список кортежей, если это необходимо.
Решим следующую задачу, демонстрирующую возможности zip(): в нашем распоряжении есть два списка, построим третий, каждый элемент которого будет формироваться как сумма элемента из первого списка и элемента из второго, умноженного на два.
>>> a = [1, 3, 5, 7, 9] >>> b = [2, 4, 6, 8, 10] >>> c = [] >>> for (x, y) in zip(a, b): c.append(x + 2 * y) >>> c [5, 11, 17, 23, 29]
Результат объединения списков с помощью функции zip() представлен ниже. Элементы исходных списков группируются попарно, образуя кортежи.
>>> a = [1, 3, 5, 7, 9] >>> b = [2, 4, 6, 8, 10] >>> list(zip(a, b)) [(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
Если в функцию zip() передать три списка, то получим кортежи, состоящие из трех элементов.
>>> a = [1, 3, 5, 7, 9] >>> b = [2, 4, 6, 8, 10] >>> c = [10, 11, 12, 13, 14] >>> list(zip(a, b, c)) [(1, 2, 10), (3, 4, 11), (5, 6, 12), (7, 8, 13), (9, 10, 14)]
В случае, когда исходные списки имеют разную длину, итоговое количество кортежей будет равно числу элементов в самом коротком списке.
>>> a = [1, 3, 5, 7, 9] >>> d = [20, 21] >>> list(zip(a, d)) [(1, 20), (3, 21)]
С помощью функции zip() можно создавать словари.
>>> a = [1, 3, 5, 7, 9] >>> keys = ['a', 'b', 'c', 'd', 'e'] >>> dict(zip(keys, a)) {'d': 7, 'c': 5, 'a': 1, 'b': 3, 'e': 9}
Используйте zip() для параллельной обработки данных и быстрого построения структур данных. Такое решение будет функциональным и лаконичным!