Рекурсивні генератори корисні для обходу нелінійних структур. Наприклад, нехай двійкове дерево буде або None, або кортеж значення, ліве дерево, праве дерево. Рекурсивний генератор - це найпростіший спосіб відвідати всі вузли. Приклад:
tree = (0, (1, None, (2, (3, None, None), (4, (5, None, None), None))),
(6, None, (7, (8, (9, None, None), None), None)))
def visit(tree):
if tree is not None:
try:
value, left, right = tree
except ValueError:
print("Bad tree:", tree)
else:
yield from visit(left)
yield value
yield from visit(right)
print(list(visit(tree)))
Змінити: замінити if tree
на, if tree is not None
щоб вловити інші помилкові значення як помилки.
Редагувати 2: про введення рекурсивних викликів у речення try: (коментар @ jpmc26).
Для поганих вузлів код вище просто реєструє ValueError і продовжує. Якщо, наприклад, (9,None,None)
замінено на (9,None)
, результат буде
Bad tree: (9, None)
[1, 3, 2, 5, 4, 0, 6, 8, 7]
Більш типовим буде ререйз після реєстрації, що робить вихідним
Bad tree: (9, None)
Traceback (most recent call last):
File "F:\Python\a\tem4.py", line 16, in <module>
print(list(visit(tree)))
File "F:\Python\a\tem4.py", line 14, in visit
yield from visit(right)
File "F:\Python\a\tem4.py", line 14, in visit
yield from visit(right)
File "F:\Python\a\tem4.py", line 12, in visit
yield from visit(left)
File "F:\Python\a\tem4.py", line 12, in visit
yield from visit(left)
File "F:\Python\a\tem4.py", line 7, in visit
value, left, right = tree
ValueError: not enough values to unpack (expected 3, got 2)
Traceback дає шлях від кореня до поганого вузла. Можна було б обернути оригіналvisit(tree)
виклик, щоб зменшити відстеження до шляху: (корінь, право, право, ліворуч, ліворуч).
Якщо рекурсивні виклики включені в речення try:, помилка повторно фіксується, реєструється та піднімається на кожному рівні дерева.
Bad tree: (9, None)
Bad tree: (8, (9, None), None)
Bad tree: (7, (8, (9, None), None), None)
Bad tree: (6, None, (7, (8, (9, None), None), None))
Bad tree: (0, (1, None, (2, (3, None, None), (4, (5, None, None), None))), (6, None, (7, (8, (9, None), None), None)))
Traceback (most recent call last):
...
Кілька звітів про журналювання, швидше за все, більше шуму, ніж допомоги. Якщо хтось хоче шлях до поганого вузла, може бути найпростішим обернути кожен рекурсивний виклик у власну спробу: clause та підняти нову помилку ValueError на кожному рівні, до цього часу виконану контур.
Висновок: якщо ви не використовуєте виняток для управління потоком (як це може бути зроблено з IndexError, наприклад), наявність та розміщення спроб: оператори залежать від повідомлення про помилку, яке потрібно.