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

2024-07-05 07:30:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我写一个程序就像下面这样

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)上运行良好,但是在我将它复制到安装了pythonv2.6.x的另一台计算机上之后,在下面列出的描述中,iterfind()不受支持

findall(match)

Finds all matching subelements, by tag name or path. Returns a list containing all matching elements in document order.

iterfind(match)

Finds all matching subelements, by tag name or path. Returns an iterable yielding all matching elements in document order.

New in version 2.7.

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


Tags: orpathnameinbytagmatchxml
3条回答

如文件所示-

  1. findall返回与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

如你链接中所说,iterfind返回一个生成器(yield),findall返回一个列表。

唯一的区别是,您可以检查here例如,查看这两种类型之间的区别。

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

如果你这样做了

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

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

如果你这样做了

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

所有元素将立即检索并存储到(临时)列表中。只有到那时,for循环才会开始遍历该列表。

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

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

相关问题 更多 >