如何使用 yield 和 generator 函数将递归函数的输出保存到项目列表

How to save the output of recursive function to list of items using yield and generator functions

我有以下来自 link 的 XML 文件作为示例:

我有以下打印输出的递归函数:

import xml.etree.ElementTree as ET

def perf_func(elem, func, level=0):
    func(elem,level)
    for child in elem.getchildren():
        perf_func(child, func, level+1)

def print_level(elem,level):
    print('-'*level+elem.tag)

elemList = ['description', 'episodes', 'movie', 'collection', 'stars', 'rating', 'year', 'type', 'format']

xmlTree = ET.parse('XML_file.xml')

下面一行打印结果:

perf_func(xmlTree.getroot(), print_level)

输出:

collection
-movie
--type
--format
--year
--rating
--stars
--description
-movie
--type
--format
--year
--rating
--stars
--description
-movie
--type

我需要将输出保存到如下所示的项目列表中。

hierarchy = [collection, -movie, --format, --year, --rating, ... ]

所以尝试了下面的修改。但无法获得列表的结果。

import xml.etree.ElementTree as ET

def perf_func(elem, func, level=0):
    func(elem,level)
    for child in elem.getchildren():
        yield from perf_func(child, func, level+1)

def print_level(elem,level):
    print ('-'*level+elem.tag)

我试图修改 print_level() 函数以提供一些可返回的输出而不是打印它,但不知道该怎么做。

perf_func(xmlTree.getroot(), print_level)

<generator object perf_func at 0x000001F6432BD2C8>

将生成器更改为 list 给我相同的输出

list(perf_func(xmlTree.getroot(), print_level))

我在其他链接中查看了类似的问题,但不太理解。

使用 yield from 但从未 yield 任何值的函数没有意义。生成器需要在某个时候填充数据才能执行任何操作。

def perf_func(elem):
    yield elem

    for child in elem.getchildren():
        yield from perf_func(child)

您可以使用 yield func(elem, level),但是将函数传递给生成器是一种有点奇怪的模式,它颠倒了责任。生成器的典型模式是懒惰地发出数据,让调用者对每个内联项应用任意处理,例如:

def traverse(elem, level=0):
    yield elem, level

    for child in elem.getchildren():
        yield from traverse(child, level + 1)

for elem, level in traverse(xmlTree.getroot()):
    print("-" * level + elem.tag) # or whatever else you want to do

在 Python 3.9 中,elem.getchildrenremoved,所以这里是对我有用的代码:

import xml.etree.ElementTree as ET

def traverse(elem, level=0):
    yield elem, level

    for child in elem:
        yield from traverse(child, level + 1)

for elem, level in traverse(ET.parse("country_data.xml").getroot()):
    print("  " * level + elem.tag) # or whatever else you want to do