На этом шаге мы рассмотрим решение этой задачи.
Вы хотите итерировать по элементам в последовательности, но первые несколько элементов вам неинтересны, и вы хотите их опустить.
В модуле itertools есть несколько функций, которые могут быть использованы для решения этой задачи. Первая - itertools.dmpwhile(). Чтобы использовать ее, вы предоставляете функцию и итерируемый объект. Возвращаемый итератор отбрасывает первые элементы в последовательности до тех пор, пока предоставленная функция возвращает True. А затем выдается вся оставшаяся последовательность.
Предположим, что вы читаете файл, который начинается со строчек с комментариями:
>>> with open('/etc/passwd') as f: for line in f: print(line, end='') ## # User Database # # Note that this file is consulted directly only when the system is running # in single-user mode. At other times, this information is provided by # Open Directory. . . . . ## nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false root:*:0:0:System Administrator:/var/root:/bin/sh >>>
Если вы хотите пропустить все начальные закомментированные строчки, вот как это можно сделать:
>>> from itertools import dropwhile >>> with open('/etc/passwd') as f: for line in dropwhile(lambda line: line.startswith('#'), f): print(line, end='')nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false root:*:0:0:System Administrator:/var/root:/bin/sh >>>
>>> from itertools import islice >>> items = ['a', 'b', 'c', 1, 4, 10, 15] >>> for x in islice(items, 3, None): print(x) 1 4 10 15 >>>
В этом примере последний аргумент islice() None необходим для того, чтобы обозначить, что вам нужно все за пределами первых трех элементов
(а не первые три элемента). То есть срез [3:], а не [:3].
Главное преимущество функций dropwhile() и islice() в том, что они позволяют избежать написания грязного кода наподобие вот такого:
with open('/etc/passwd') as f: # Пропускаем начальные комментарии while True: line = next(f, '') if not line.startswith('#'): break # Обрабатываем оставшиеся строки while line: # Можно заменить полезной обработкой print(line, end='') line = next(f, None)
Отбрасывание первой части итерируемого объекта также немного отличается от простого фильтрования. Например, первая часть этого рецепта может быть переписана вот так:
with open('/etc/passwd') as f: lines = (line for line in f if not line.startswith('#')) for line in lines: print(line, end='')
Очевидно, что это отбросит все закомментированные строчки в начале файла, но такое решение отбросит и все остальные такие строчки во всем файле. С другой стороны, решение, которое отбрасывает все элементы до тех пор, пока не будет встречен элемент, не соответствующий условиям отбрасывания, подходит под наши требования: все последующие элементы будут возвращены без фильтрования.
Стоит отметить, что этот рецепт работает со всеми итерируемыми объектами, включая те, размер которых нельзя оценить предварительно: генераторами, файлами и другими подобными объектами.
На следующем шаге мы рассмотрим итерирование по всем возможным комбинациям и перестановкам.