Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs
Следующая
функция zip_longest() модуля itertools работает по
аналогии со встроенной функцией zip() языка Python, но в отличие
от нее перебирает все элементы указанных последовательностей, заполняя
недостающие значения заданным значением (по умолчанию None). Давайте
рассмотрим ее работу на конкретных примерах.
Пусть в
программе заданы следующие итерируемые объекты:
header = ['id', 'name', 'old', 'job']
row1 = (1, 'Sergey', 34, 'teacher')
row2 = (2, 'Olga', 29)
row3 = (3, 'Maxim')
Переберем их с
помощью функции zip_longest():
from itertools import zip_longest
joined_it = zip_longest(header, row1, row2, row3)
lst = list(joined_it)
print(*lst, sep='\n')
В консоли увидим
следующий список из кортежей:
[('id',
1, 2, 3), ('name', 'Sergey', 'Olga', 'Maxim'), ('old', 34, 29, None), ('job',
'teacher', None, None)]
Первый кортеж
содержит первые элементы последовательностей, второй – вторые, и так далее.
Если каких-либо значений недостает, то они заменяются значением None. При
необходимости его можно поменять на любое другое с помощью параметра fillvalue. Например:
joined_it = zip_longest(header, row1, row2, row3, fillvalue='нет данных')
В результате,
получим:
[('id', 1, 2,
3), ('name', 'Sergey', 'Olga', 'Maxim'), ('old', 34, 29, 'нет данных'), ('job',
'teacher', 'нет данных', 'нет данных')]
Во всем
остальном функция zip_longest() работает по аналогии с
функцией zip(), о которой мы
подробно говорили в базовом курсе по языку Python.
Функция zip_longest() может быть
полезна в следующих случаях:
- Объединение
разнородных наборов данных. Если данные поступают из различных источников и
имеют разную длину, то удобно использовать zip_longest(), чтобы не потерять
важную информацию.
- Обработка файлов
или баз данных. Часто встречается ситуация, когда таблицы содержат разное
количество записей, и их необходимо сопоставлять, сохраняя всю доступную
информацию.
- Создание
конфигураций. Когда разные настройки применяются к разным частям системы, важно
учесть случаи отсутствия значений.
Функция islice()
Как вы знаете,
любая упорядоченная последовательность языка Python (списки,
кортежи) поддерживают операции взятия срезов. Например, для списка:
marks = [2, 5, 3, 2, 1, 5, 3]
можно легко
выбрать элементы через один:
marks[::2] # [2, 3, 1, 3]
или получить
элементы со 2-го по 4-й:
и так далее. Все
эти операции вам уже известны. Однако, например, с неупорядоченными
последовательностями:
такие операции
выполнить нельзя:
s[1:3] # TypeError: 'set' object is not subscriptable
Но не для
функции islice(), которая
позволяет применять аналогичные операции взятия срезов для любых итерируемых
последовательностей. Эта функция имеет следующее определение:
islice(iterable,
start[, stop[, step]])
и возвращает
итератор, с помощью которого можно выбирать элементы среза. Например, для
множества s
ее
можно записать так:
it_s = islice(s, 1, 3) # аналог s[1:3]
и выбрать все
элементы, например, в список:
Конечно, порядок
следования элементов оказывается непредсказуемым, т.к. работа ведется с
множеством. Но для упорядоченных коллекций будем получать предсказуемые
результаты. Например, для последовательностей:
d = {'first': 1, 'second': 2, 'third': 3}
tp = (1, 2, 3, 4, 5, 6, 7)
r = range(20)
g = (x ** 2 for x in range(10))
имеем:
list(islice(d, 2)) # аналог d[:2]
list(islice(tp, 0, len(tp), 2)) # аналог tp[::2]
list(islice(r, 2, 15, 3)) # аналог r[2:15:3]
list(islice(g, 0, 5, 2)) # аналог g[0:5:2]
Здесь функция islice() применяется к
объектам range() и генератору g(), к которым
обычные срезы неприменимы.
Таким образом,
функция islice() обладает
следующими преимуществами по сравнению с обычными срезами:
- Эффективное
использование памяти. Не создает промежуточных структур данных, работает
непосредственно с исходным объектом.
- Универсальность.
Подходит для любых итерируемых объектов, включая бесконечные генераторы.
- Гибкость. Позволяет
выбрать нужный фрагмент данных без модификации самой структуры данных.
Функция tee()
В заключение
этого занятия рассмотрим еще одну функцию tee(), которая предназначена
для дублирования итератора, создавая один или несколько его независимых копий.
Это полезно когда нужно одновременно обрабатывать одни и те же элементы последовательности
разными способами или использовать разные методы обработки элементов одного и
того же исходного итератора.
Пусть в
программе имеется следующий список:
symbols = list("python") # ['p', 'y', 't', 'h', 'o', 'n']
Для его перебора
можно сформировать итератор:
и прописать в
цикле for:
for a in it:
print(a, end=" ")
Но, второй раз использовать
этот же итератор не получится, еще один цикл for завершится
сразу:
for x in it: # не cработает ни разу
print(x, end=" ")
При реализации
такой логики нужны два независимых итератора. Причем, именно независимых.
Например, если вначале определить второй, просто как еще одну переменную:
И во втором
операторе цикла указать этот второй итератор:
for x in it2: # не отработает ни разу
print(x, end=" ")
то, как вы
понимаете, ничего не изменится, т.к. it2 и it – это ссылки на
один и тот же объект, на один итератор. Так вот, чтобы создать именно копии
итераторов удобно использовать функцию tee(), например,
так:
или так:
в обоих случаях
получим два независимых итератора it1, it2 для перебора
списка symbols. В этом легко
убедиться, если выполнить следующий цикл for:
for a, b in zip(it1, it2):
print(a, b)
В консоли увидим
следующий результат вывода:
p
p
y
y
t
t
h
h
o
o
n n
Список
действительно был пройден дважды итераторами it1, it2.
Однако всегда
следует помнить, что итераторы it1, it2 зависимы от
исходного итератора it. Если изменить его состояние, например, выбрать
первый элемент:
то в цикле for список будет
перебираться, начиная со второго элемента.
По умолчанию
функция tee() возвращает
два новых независимых итератора. Если нам требуется большее их количество, то
это следует указать вторым аргументом, например, так:
it1, it2, t3 = tee(it, 3)
Тогда в цикле:
for a, b, c in zip(it1, it2, t3):
print(a, b, c)
список symbols будет перебираться
трижды.
Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs