如果存在yield,Python 会跳过递归

问题描述 投票:0回答:1

我有以下 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:okp="okapi-framework:xliff-extensions" xmlns:its="http://www.w3.org/2005/11/its" xmlns:itsxlf="http://www.w3.org/ns/its-xliff/" its:version="2.0">
<file original="temp/file_conversion/tmp4a9kn6bn/69502fea-751c-4c3c-a38a-4fce9e13ebde.txt" source-language="en" target-language="ar" datatype="x-text/plain" okp:inputEncoding="UTF-8">
<body>
<trans-unit id="1idhasofh" xml:space="preserve">
<source xml:lang="en">foo<bpt id="0">&lt;bar&gt;</bpt>&lt;Instruction><ept id="0">&lt;crow&gt;</ept>&lt;grande&gt;</source>
<target xml:lang="ar">foo<bpt id="0">&lt;bar&gt;</bpt>&lt;Instruction><ept id="0">&lt;crow&gt;</ept>&lt;grande&gt;</target>
</trans-unit>
</body>
</file>
</xliff>

我正在尝试创建一个函数来解析我已读入 ElementTree.Element 的 XML 文件:

from xml.etree import ElementTree as ET


def parse_xml(ele: ET.Element):
    tag = ele.tag
    if not isinstance(tag, str) and tag is not None:
        return
    t = ele.text
    if t:
        yield t
    for e in ele:
        parse_xml(e)
        t = e.tail
        if t:
            yield t

def main():
    fp = "path/to/xml"
    tree = ET.parse(fp)
    root = tree.getroot()

    t_units = root.findall(".//{*}trans-unit")
    for source, target in t_units:
        for ele in parse_xml(source):
            print(ele)

我得到:

foo
<Instruction>
<grande>

在我的调试器中,我看到

parse_xml(e)
被跳过。当我用打印语句替换产量时:

def parse_xml(ele: ET.Element):
    tag = ele.tag
    if not isinstance(tag, str) and tag is not None:
        return
    t = ele.text
    if t:
        print(t)
    for e in ele:
        parse_xml(e)
        t = e.tail
        if t:
            print(t)

我得到了预期的结果(到达所有标记的文本):

foo
<bar>
<Instruction>
<crow>
<grande>

为什么yield会出现这种情况?

python xml yield
1个回答
0
投票

parse_xml
是一个生成器函数 - 当它被调用时,它不会运行:相反,它将返回一个必须迭代的生成器,就像对
parse_xml
的根调用在
   for ele in parse_xml(source):
行中迭代一样在你的主要方法中。

此外,

parse_xml
调用会立即返回生成器,而不在函数内运行任何代码 - 它是
for
语句,它实际上运行函数内的代码并将其前进到
yield
语句。

因此,您可以在每个递归 parse_xml 调用中循环返回值,如下所示:

def parse_xml(ele: ET.Element):
    ...
    for e in ele:
        for inner_e in parse_xml(e):
            yield inner_e
        t = e.tail
        if t:
            yield t

或者,您可以使用 Python 的语法结构

yield from
来进行深层嵌套(或递归)生成器调用 - 这会更高效(并且对于使用其他功能的生成器还有其他优点,例如接受来自运行生成器的调用者函数)。这是推荐的方法:

def parse_xml(ele: ET.Element):
    tag = ele.tag
    if not isinstance(tag, str) and tag is not None:
        return
    t = ele.text
    if t:
        yield t
    for e in ele:
        yield from parse_xml(e)
        t = e.tail
        if t:
            yield t

yield from
用于对
parse_xml
的内部调用的返回值,如此处将做“正确的事情”:推迟外部(当前)parse_xml调用的执行,并隧道内部调用产生的每个值到它的调用者 - 当内部调用结束时(它产生一个
StopIteration
:与创建
for
循环相同的机制stop),外部调用的执行将恢复。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.