#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