Rekursive Generatoren sind nützlich, um nichtlineare Strukturen zu durchlaufen. Angenommen, ein Binärbaum ist entweder Keine oder ein Wertetupel, linker Baum, rechter Baum. Ein rekursiver Generator ist der einfachste Weg, alle Knoten zu besuchen. Beispiel:
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)))
Bearbeiten: Ersetzen if tree
durch if tree is not None
, um andere falsche Werte als Fehler abzufangen.
Bearbeiten 2: Informationen zum Einfügen der rekursiven Aufrufe in die try: -Klausel (Kommentar von @ jpmc26).
Bei fehlerhaften Knoten protokolliert der obige Code nur den ValueError und fährt fort. Wenn zum Beispiel (9,None,None)
durch ersetzt wird (9,None)
, ist die Ausgabe
Bad tree: (9, None)
[1, 3, 2, 5, 4, 0, 6, 8, 7]
Typischer wäre es, nach der Protokollierung erneut zu erhöhen, sodass die Ausgabe erfolgt
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)
Der Traceback gibt den Pfad von der Wurzel zum fehlerhaften Knoten an. Man könnte den ursprünglichen visit(tree)
Aufruf umbrechen, um den Traceback auf den Pfad zu reduzieren: (root, right, right, left, left).
Wenn die rekursiven Aufrufe in der try: -Klausel enthalten sind, wird der Fehler auf jeder Ebene des Baums erneut erfasst, protokolliert und erneut ausgeführt.
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):
...
Die mehreren Protokollierungsberichte sind wahrscheinlich mehr Rauschen als Hilfe. Wenn der Pfad zum fehlerhaften Knoten gewünscht wird, ist es möglicherweise am einfachsten, jeden rekursiven Aufruf in einer eigenen try: -Klausel zu verpacken und auf jeder Ebene einen neuen ValueError mit dem bisher erstellten Pfad auszulösen.
Schlussfolgerung: Wenn keine Ausnahme für die Flusskontrolle verwendet wird (wie dies beispielsweise bei IndexError der Fall ist), hängt das Vorhandensein und die Platzierung von try: -Anweisungen von der gewünschten Fehlerberichterstattung ab.