xml.etree.ElementTree 插入子节点的子节点创建无限循环 Python

xml.etree.ElementTree insert into child of child node creating infinity loop Python

我试图在大型 XML 文档(~2000 行)中的子节点的特定子节点插入一个元素,下面是我的代码:

import xml.etree.cElementTree as ET
class Kapow_commands:
    tree = ET.parse('location/of/xml/file')
    root = tree.getroot()
    seq_id = 39

    def __init__(self):
        pass

    def append(self, block):
        node_num=0 
        for node in Kapow_commands.root[13][1]:
            node_num=node_num+1
            if node.get('class') == 'End':
                node.attrib['id'] = str(Kapow_commands.seq_id + 1)
                print(node.attrib)
                print(node_num)
                Kapow_commands.root[13][1].insert(node_num -1, block)


block = ET.Element("test")    

Kapow_commands().append(block)

此代码在特定节点扫描 XML 文件以获得 class = 'End',然后将 1 添加到该元素 ID 并在它之前插入另一个元素。但是,当我 运行 这似乎创建了一个无限循环,因为它不会停止在此位置插入元素。有谁知道为什么会这样?或者关于如何在所需位置正确插入此元素的任何想法?

我遇到了类似的问题。

解决方案是将要附加的元素的初始化放在循环中。

所以在你的情况下,我会传递一个名称作为参数,代码如下所示:

def append(self, blockName): # here comes the name
    node_num=0 
    for node in Kapow_commands.root[13][1]:
        block = ET.Element(name) # and there goes the init
        node_num=node_num+1
        if node.get('class') == 'End':
            node.attrib['id'] = str(Kapow_commands.seq_id + 1)
            print(node.attrib)
            print(node_num)
            Kapow_commands.root[13][1].insert(node_num -1, block)

对我来说,它成功了。不幸的是,我不知道这个魔法背后的原因。

修正

如您评论中所述,在插入新元素后插入 break 语句可解决无限循环问题。

为什么代码会产生死循环

至于为什么会出现无限循环,我们需要了解在python中调用for循环时会发生什么。从 docs 我们看到 for 循环在您的可迭代对象上创建了一个迭代器,在本例中为 Kapow_commands.root[13][1],当我们跳出它、序列为空或迭代器引发时终止StopIteration 异常。实际上,如果我们将 for node in Kapow_commands.root[13][1]: 展开,我们会得到类似于

的结果
iterator = iter(Kapow_commands.root[13][1])
while True:
    try:
        node  = iterator.__next__()
        # Body of for loop
    except StopIteration:
        break

这就是神奇的地方。让我们用 'End' End Node 的 class 调用节点。如果我们当前的节点是End Node,我们执行Kapow_commands.root[13][1].insert(node_num -1, block)。这会将 block 插入到 我们可迭代对象 中的当前位置,这意味着可迭代对象中的下一项再次变为 End Node 。在 for 循环的下一次迭代中,iterator.__next__() 给我们 End Node 并且我们回到开始的地方,产生一个无限循环。