Почему sentinel является обязательным в этом вызове iter?

#python

#python

Вопрос:

Я не привык видеть sentinel при преобразовании итерируемого объекта в итератор. Вот код, который я анализирую:

 import re
NAME = r'(?P<NAME>[a-zA-Z_][a-zA-Z_0-9]*)'
NUM  = r'(?P<NUM>d )'
PLUS = r'(?P<PLUS> )'
TIMES = r'(?P<TIMES>*)'
EQ    = r'(?P<EQ>=)'
WS    = r'(?P<WS>s )'
master_pat = re.compile('|'.join([NAME, NUM, PLUS, TIMES, EQ, WS]))

from collections import namedtuple
Token = namedtuple('Token', ['type','value'])

def generate_tokens(pat, text):
    import pdb;pdb.set_trace()
    scanner = pat.scanner(text)
    for m in iter(scanner.match,None):
        yield Token(m.lastgroup, m.group())
# Example use
for tok in generate_tokens(master_pat, 'foo = 42'):
    print(tok)
  

Почему sentinel является обязательным?
Я не ожидал увидеть эту ошибку:

 (Pdb) it2=iter(scanner.match)     
*** TypeError: 'builtin_function_or_method' object is not iterable
  

Комментарии:

1. Метод scanner.match не является итеративным. В общем, for x in iter(y) в любом случае это лишнее, при for самостоятельном вызове iter ( for x in y идентично).

2. @L3viathan итак, если метод scanner.match не является итеративным, мы создаем итерацию с помощью функции iter. Я не понимаю, как это работает, я не могу применить этот процесс к какому-либо методу…

3.Вы не можете просто сделать итерацию из чего угодно. Результат вызова scanner.match является итеративным, но вам все равно не нужно вызывать iter() явно : for m in scanner.match(): ... .

4. Я попробовал предложенный синтаксис, который не работает на моей стороне: >>> для m в scanner.match(): … print(m) … Трассировка (последний последний вызов): файл «<stdin>», строка 1, в <module> Ошибка типа: ‘re. Объект Match’ не является итеративным

Ответ №1:

Справка для встроенной функции iter гласит:

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

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

Во второй форме (как видно из вопроса) первый переданный аргумент iter является вызываемым. iter требуется аргумент sentinel, чтобы определить, когда прекратить вызов вызываемого объекта.

Вторая форма эквивалентна:

 def iter(some_func, sentinel):
    while True:
        retval = some_func()
        if retval == sentinel:
            break
        yield retval