iter(object, sentinel)
object
- последовательность или итератор,sentinel
- значение с которым будет вызываться каждый элемент из object
(если элементы object
- это вызываемые объекты).iterator
- объект итератора.Функция iter()
возвращает объект итератора. Первый аргумент object
интерпретируется по-разному, в зависимости от наличия второго аргумента sentinel
.
Если НЕТ аргумента sentinel
, то первый аргумент object
должен быть объектом-коллекцией, которая поддерживает протокол итераций метод __iter__()
или он должен поддерживать протокол последовательности метод __getitem__()
с целыми аргументами, начиная с 0
. Если он не поддерживает любой из этих протоколов, бросается исключение TypeError
.
Если передается аргумент sentinel
, то ожидается, что первый аргумент object
, поддерживает вызов __call__()
. В этом случае, созданный итератор будет вызывать указанный объект с каждым обращением к своему __next__()
и проверять полученное значение на равенство со значением, переданным в аргумент sentinel
. Если полученное значение равно sentinel
, то бросается исключение StopIteration
, иначе возвращается полученное значение.
Встроенная функция iter
с двумя аргументами более или менее эквивалентна этой функции-генератору:
def iter(func, target_value): while target_value != (value := func()): yield value
x = iter(["apple", "banana", "cherry"]) print(next(x)) print(next(x)) print(next(x))
Одно из применений второго аргумента sentinel
это чтение строк файла, пока не будет достигнута, переданная в sentinel
. Следующий пример считывает файл, пока метод readline()
не вернёт пустую строку:
with open('mydata.txt') as fp: # читаем, пока не попадется пустая строка for line in iter(fp.readline, sentinel=''): # Делаем что-то с line.
Пользовательский тип, определивший __call__()
:
class MyIterable(object): def __init__(self): self.index = 0 self.items = [1, 2, 3, 4] def __call__(self): value = self.items[self.index] self.index += 1 return value x = iter(MyIterable(), 3) print(next(x)) # 1 print(next(x)) # 2 print(next(x)) # StopIteration
Версия iter(function, value)
создаст итератор, который возвращает последовательные возвращаемые значения вызова function
пока одно из них не совпадет с value
, после чего итератор завершается. Например, используя функцию input
, можно создать цикл, который будет печатать текст по нажатию Enter
и будет делать это до тех пор пока пользователь не введет exit
.
for user_str in iter(input, "exit"): # Обработка ввода пользователя... print(f"Пользователь ввел {user_str!r}.")
Чтобы увидеть цикл в действии, скопируйте и вставьте приведенный выше код в интерпретатор и введите пару строк.
В документации показан еще один пример использования iter
этого способа для создания "считывателя фрагментов", например, для чтения фрагментов из сокета:
from functools import partial for block in iter(partial(sock.recv, 64), b""): # Блок 64 байта...
Приведенный выше цикл будет считывать фрагменты по 64 байта из сокета до тех пор, пока не останется ничего для считывания.
Другой пример использования - в контексте симуляций, где необходимо запустить симуляцию, пока случайное число не достигнет определенного значения. Например, бросание кубика, пока не выпадет число 6:
from random import randint def roll(): return randint(1, 10) for die_roll in iter(roll, 6): # процесс бросания. print(die_roll) print('Выпало число 6')
Помним, что тип итератора
iterator
"кончаем", т.е. он исчерпывается/заканчивается и для повторной итерации его нужно снова инициировать.