lxml.etree.iterparse 会关闭输入文件处理器吗?

5 投票
2 回答
757 浏览
提问于 2025-04-16 22:10

filterous正在使用iterparse来解析一个简单的XML的StringIO对象,这是在一个单元测试中进行的。然而,当尝试在之后访问这个ValueError: I/O operation on closed file”的错误。根据iterparse的文档,"从lxml 2.3开始,.close()方法也会在出错的情况下被调用",但我并没有从iterparse那里收到任何错误信息或Exception。看来我的输入输出知识显然不够,所以有没有人能给点建议呢?

命令和(希望)相关的代码:

$ python2.6 setup.py test

setup.py:

from setuptools import setup
from filterous import filterous as package

setup(
    ...
    test_suite = 'tests.tests',

tests/tests.py:

from cStringIO import StringIO
import unittest

from filterous import filterous

XML = '''<posts tag="" total="3" ...'''

class TestSearch(unittest.TestCase):
    def setUp(self):
        self.xml = StringIO(XML)
        self.result = StringIO()
    ...
    def test_empty_tag_not(self):
        """Empty tag; should get N results."""
        filterous.search(
            self.xml,
            self.result,
            {'ntag': [u'']},
            ['href'],
            False)
        self.assertEqual(
            len(self.result.getvalue().splitlines()),
            self.xml.getvalue().count('<post '))

filterous/filterous.py:

from lxml import etree
...
def search(file_pointer, out, terms, includes, human_readable = True):
    ...
    context = etree.iterparse(file_pointer, tag='posts')

错误追踪信息:

ERROR: Empty tag; should get N results.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/victor/dev/filterous/tests/tests.py", line 149, in test_empty_tag_not
    self.xml.getvalue().count('<post '))
ValueError: I/O operation on closed file

附言:所有测试在2010-07-27时都运行得很好。

2 个回答

0

问题出在文档上。你引用的“从lxml 2.3开始,.close()方法在出错时也会被调用”跟iterparse没有关系。这个内容出现在你链接的页面上,iterparse部分之前。它是关于目标解析器接口的文档,指的是目标(输出!)对象的close()方法,跟你的StringIO没关系。无论如何,你似乎也忽略了那个小词。在2.3之前,lxml只有在解析成功时才会关闭目标对象。现在,它会在出错时关闭。

你为什么想在解析完成后“访问”StringIO对象呢?

更新 你是指在之后访问数据库时,所有那些self.xml.getvalue()的调用吗?[请在你的问题中显示完整的错误追踪信息,这样我们就不用猜了!] 如果这导致了问题(这确实算是一个IO操作),那就忘了getvalue()吧……如果它能正常工作,难道不会返回那个(命名不太常规的)(不变的)XML吗?

1

看起来用 StringIO 运行得很好,试试用这个代替 cStringIO。我也不知道为什么它会被关闭。

撰写回答