Операторы итерации в питоне

№20 Итераторы Python / Уроки по Python для начинающих

List, tuple, dict и sets — это все итерируемые объекты. Они являются итерируемыми контейнерами, из которых вы можете получить итератор. Все эти объекты имеют метод iter() , который используется для получения итератора.
Получим итератор из кортежа и выведем каждое значение:

mytuple = ("яблоко", "банан", "вишня") myit = iter(mytuple) print(next(myit)) print(next(myit)) print(next(myit)) 

Даже строки являются итерируемыми объектами и могут возвращать итератор.

mystr = "банан" myit = iter(mystr) print(next(myit)) print(next(myit)) print(next(myit)) print(next(myit)) print(next(myit)) 

Цикл через итератор

Мы также можем использовать цикл for для итерации по итерируему объект.

mytuple = ("яблоко", "банан", "вишня") for x in mytuple: print(x) 

Итерируйем символы строки:

mystr = "банан" for x in mystr: print(x) 

Цикл for фактически создает объект итератора и выполняет метод next() для каждого цикла.

Создание итератора

Чтобы создать объект/класс в качестве итератора, вам необходимо реализовать методы __iter__() и __next__() для объекта.

Как вы узнали из урока «Классы и объекты Python», у всех классов есть функция под названием __init__() , которая позволяет вам делать инициализацию при создании объекта.

Метод __iter__() действует аналогично, вы можете выполнять операции (инициализацию и т. Д.), Но всегда должны возвращать сам объект итератора. Метод __next __ () также позволяет вам выполнять операции и должен возвращать следующий элемент в последовательности.

Создайте итератор, который возвращает числа, начиная с 1, и увеличивает на единицу (возвращая 1,2,3,4,5 и т. д.):

class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): x = self.a self.a += 1 return x myclass = MyNumbers() myiter = iter(myclass) print(next(myiter)) print(next(myiter)) print(next(myiter)) print(next(myiter)) print(next(myiter)) 

StopIteration

Приведенный выше пример будет продолжаться вечно, пока вы вызываете оператор next() или если используете в цикле for . Чтобы итерация не продолжалась вечно, мы можем использовать оператор StopIteration .

В метод __next __() мы можем добавить условие завершения, чтобы вызвать ошибку, если итерация выполняется указанное количество раз:

class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): if self.a  20: x = self.a self.a += 1 return x else: raise StopIteration myclass = MyNumbers() myiter = iter(myclass) for x in myiter: print(x) 

Источник

Итераторы#

Итераторы позволяют обойти все элементы итерируемых объектов и по всюду используются в python .

Итератор ( iterator ) — это объект, который должен определить метод __next__ (т.е. реагировать на функцию next), выдавать следующий элемент коллекции по вызову этого метода и бросать исключение StopIteration, когда эти элементы исчерпались.

Стандартный итератор#

Получить стандартный итератор по коллекции можно встроенной функцией iter.

a_list = list(range(3)) iterator = iter(a_list) print(iterator) 

В ячейке выше объявлен список a_list = [0, 1, 2] , а далее с помощью вызова функции iter создан стандартный итератор iterator по нему. Теперь у этого итератора можно спросить следующий элемент списка функцией next.

Первый вызов функции next возвращает первый элемент контейнера, от которого создан контейнер.

Второй вызов функции next — второй элемент списка.

Третий вызов — третий элемент списка.

--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) Cell In [9], line 1 ----> 1 d = next(iterator) 2 print(d) StopIteration:

Четвертый вызов функции next должен вернуть четвертый элемент, но т.к. список a_list содержит всего 3 элемента, то итератор уже исчерпан и возбуждается исключение StopIteration .

Вообще говоря, можно изменить список при итерации по нему, но желательно по возможности избегать этого.

iterator = iter(a_list) a = next(iterator) a_list.insert(0, 42) b, c, d = next(iterator), next(iterator), next(iterator) print(a, b, c, d) print(a_list) 

Цикл for использует итераторы для прохода по итерируемым объектам и сам вызывает функцию next до тех пор, пока не встретит исключение StopIteration .

Среди итерируемых объектов мы уже встречались с

  • все последовательности: списки, кортежи, строки, range и т.п.;
  • множества, словари и все связанные с ними view ( dict_keys , dict_values и dict_items );
  • массивы NumPy ;
  • таблицы и столбцы pandas .

Нестандартные встроенные итераторы#

В python существуют разные итераторы, которые могут пригодиться для разных целей, например, для того чтобы пробежаться по коллекции в другом порядке.

reversed #

Встроенная функция reversed создаёт итератор, который пробегает по коллекции в обратном порядке относительно стандартного итератора iter .

x = [1, 2, 3] reversed_iterator = reversed(x) print(reversed_iterator) print(list(reversed_iterator)) 

enumerate #

Встроенная функция enumerate возвращает “нумерующий итератор”, т.е. итератор, который помимо следующего элемента контейнера возвращает ещё и его номер.

L = list("abc") enumerated_iterator = enumerate(L) print(L) print(enumerated_iterator) print(list(enumerated_iterator)) 

Часто используется в циклах, если нужен доступ к элементам контейнера по индексу. При этом, следующая запись

for i, _ in enumerate(iterable): . 

считается предпочтительнее, чем

for i in range(len(iterable)): . 
for i, x in enumerate(L): print(i, x) 

Конечно, эти итераторы можно комбинировать.

for i, x in enumerate(reversed(L)): print(i, x) 

zip #

Встроенная функция zip создаёт итератор по нескольким итерируемым объектам, т.е. позволяет пробежаться по нескольким контейнерам одновременно.

В случае двух контейнеров название функции zip хорошо иллюстрирует принцип её действия.

X = "ABC" Y = [1, 2, 3] zip_XY = zip(X, Y) print(zip_XY) print(list(zip_XY)) 

В ячейке выше приведен пример с двумя коллекциями X и Y . В общем случае можно передавать произвольное количество коллекций в функцию zip . Типичное её применение в цикле выглядит следующем образом.

for x1, x2, . , xn in zip(X1, X2, . , Xn): . 
for i, x, y in zip(range(len(X)), X, Y): print(f"i>: x=>, y=>") 

Предыдущий цикл можно заменить конструкцией вида.

for i, (x, y) in enumerate(zip(X, Y)): print(f"i>: x=>, y=>") 

Функция zip может быть использована для того, чтобы пробежаться по столбцам матрицы, т.е. как бы транспонировать её.

m = [ [11, 12, 13], [21, 22, 23], ] for row in m: print(row) print() for column in zip(*m): print(column) 
[11, 12, 13] [21, 22, 23] (11, 21) (12, 22) (13, 23)

Если коллекции внутри zip содержат разное количество элементов, то итерация прекратится, как только закончится элементы в самом коротком из них, а функция zip_longest из модуля стандартной библиотеки itertools позволяет итерировать до упора, пока хотя бы в одной последовательности остались элементы.

Модуль itertools #

В модуле itertools определен ещё ряд полезных итераторов. Рассмотрим несколько из них.

zip_longest #

Если коллекции внутри zip содержат разное количество элементов, то итерация прекратится, как только закончится элементы в самом коротком из них, а функция zip_longest из модуля itertools позволяет итерировать до упора, пока хотя бы в одной последовательности остались элементы.

from string import ascii_letters, digits from itertools import zip_longest for x, y in zip(digits, ascii_letters): print(f"x>->y>, ", end="") print() for x, y in zip_longest(digits, ascii_letters, fillvalue=float("NaN")): print(f"x>->y>, ", end="") 
0->a, 1->b, 2->c, 3->d, 4->e, 5->f, 6->g, 7->h, 8->i, 9->j, 0->a, 1->b, 2->c, 3->d, 4->e, 5->f, 6->g, 7->h, 8->i, 9->j, nan->k, nan->l, nan->m, nan->n, nan->o, nan->p, nan->q, nan->r, nan->s, nan->t, nan->u, nan->v, nan->w, nan->x, nan->y, nan->z, nan->A, nan->B, nan->C, nan->D, nan->E, nan->F, nan->G, nan->H, nan->I, nan->J, nan->K, nan->L, nan->M, nan->N, nan->O, nan->P, nan->Q, nan->R, nan->S, nan->T, nan->U, nan->V, nan->W, nan->X, nan->Y, nan->Z,

product #

Итератор product позволяет итерировать по декартову (или внешнему) произведению других итерируемых объектов. В некоторых ситуациях позволяет упростить конструкции из вложенных циклов.

from itertools import product X = [0, 1, 2] Y = "abc" print([(x, y) for x in X for y in Y]) print(list(product(X, Y))) 
[(0, 'a'), (0, 'b'), (0, 'c'), (1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c')] [(0, 'a'), (0, 'b'), (0, 'c'), (1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c')]

permutations #

Итератор permutations пробегается по списку всех возможных перестановок итерируемого аргумента.

from itertools import permutations print(list(permutations("abc"))) 
[('a', 'b', 'c'), ('a', 'c', 'b'), ('b', 'a', 'c'), ('b', 'c', 'a'), ('c', 'a', 'b'), ('c', 'b', 'a')]

Сгенерировать случайную перестановку можно методом shuffle или методом sample при k равном длине последовательности. shuffle случайным образом тасует элементы на месте, а sample возвращает новый список.

combinations и combinations_with_replacements #

Метод combinations возвращает все возможные способы выбрать r элементов итерируемого объекта без повторов.

from itertools import combinations for x, y in combinations(range(3), 2): print(f"x> and y>") 

Метод combinations_with_replacements делает то же самое, но допускает повторы.

from itertools import combinations_with_replacement for x, y in combinations_with_replacement(range(3), 2): print(f"x> and y>") 
0 and 0 0 and 1 0 and 2 1 and 1 1 and 2 2 and 2

Основы списковых включений

Источник

Читайте также:  Javascript строка по формату
Оцените статью