xml.etree.ElementTree 的 findall() 和 iterfind() 有什么区别



>我用下面这样编写一个程序

from xml.etree.ElementTree import ET
xmlroot = ET.fromstring([my xml content])
for element in xmlroot.iterfind(".//mytag"):
    do some thing

它在我的 Python (v2.7.1( 上运行良好,但在我将其复制到另一台安装了 Python v2.6.x 的计算机后,iterfind()不支持,在 Python 文档中,下面列出了描述

查找全部(匹配(

按标记名称或路径查找所有匹配的子元素。返回一个列表,其中包含按文档顺序排列的所有匹配元素。

迭代查找(匹配(

按标记名称或路径查找所有匹配的子元素。返回一个可迭代对象,按文档顺序生成所有匹配元素。

版本 2.7 中的新功能。

我的问题是:这两个函数是否相同? 这两个函数有什么区别

如文档中所示 -

  1. findall返回match xpath匹配元素的完整列表,我们可以使用下标来访问它们,示例 -

    >>> root = ET.fromstring("<a><b>c</b></a>")
    >>> root.findall("./b")
    [<Element 'b' at 0x02048C90>]
    >>> lst = root.findall("./b")
    >>> lst[0]
    <Element 'b' at 0x02048C90>
    

我们还可以使用 for 循环来遍历列表。

  1. IterFind 返回一个迭代器(生成器(,它不返回列表 ,在这种情况下我们不能使用下标来访问元素,我们只能在接受迭代器的地方使用它,一个例子是在 for 循环中。

在您实际上想要遍历返回的列表的情况下,IterFind 会比 findall 更快(根据我的经验,这是大部分时间(,因为 findall 必须在返回之前创建完整的列表,而 iterfind 仅在迭代和调用 next(iter) 时找到(产生(下一个与match匹配的元素(这是使用 for 或此类结构遍历列表时内部调用的元素(。

在您想要列表的情况下,两者似乎具有相似的时间。

两种情况的性能测试 -

In [1]: import xml.etree.ElementTree as ET
In [2]: x = ET.fromstring('<a><b>c</b><b>d</b><b>e</b></a>')
In [3]: def foo(root):
   ...:     d = root.findall('./b')
   ...:     for  y in d:
   ...:         pass
   ...: 
In [4]: def foo1(root):
   ...:     d = root.iterfind('./b')
   ...:     for y in d:
   ...:         pass
   ...: 
In [5]: %timeit foo(x)
100000 loops, best of 3: 9.24 µs per loop
In [6]: %timeit foo1(x)
100000 loops, best of 3: 6.65 µs per loop
In [7]: def foo2(root):
   ...:     return root.findall('./b')
   ...: 
In [8]: def foo3(root):
   ...:     return list(root.iterfind('./b'))
   ...: 
In [9]: %timeit foo2(x)
100000 loops, best of 3: 8.54 µs per loop
In [10]: %timeit foo3(x)
100000 loops, best of 3: 8.4 µs per loop

如果你这样做

for element in xmlroot.iterfind(".//mytag"):
    do some thing

然后,将从 XML 文件中一次检索一个元素(每个循环一个元素(。

如果你这样做

for element in xmlroot.findall(".//mytag"):
    do some thing

所有元素将立即检索并存储到(临时(列表中。只有这样,for循环才会开始迭代该列表。

这意味着第二种方法在开始时需要更长的时间(因为它必须构建该列表(并使用更多内存(同样的原因(。此外,如果您需要在到达最后一个元素之前退出 for 循环,您将完成不必要的工作。另一方面,一旦你进入for循环,第二种方法可能会更快一些。通常,第一种方法("惰性评估"(的好处超过了这个缺点。

在您的情况下,切换到 findall 可能是安全的。

正如您的链接中所述,iterfind 返回一个生成器(yield(,findall 返回一个列表。

唯一的区别是在那里,例如,您可以在此处查看这两种类型之间的区别。

在这种情况下,这主要是内存性能。

最新更新