怎么能" t = foo();用t"与foo()"不同于"?

时间:2018-04-13 05:05:42

标签: python-3.x cpython

我正在测试程序转换工具。它导致其中一项CPython测试失败,但我不能为我的生活找出原因。

这是CPython测试套件https://github.com/python/cpython/blob/master/Lib/test/test_sax.py#L143中test_sax.py中的一个测试的缩小版本。此代码段会写入一个XML文件,然后以错误的编码方式将其读回。这会导致xml.sax.parse失败并引发异常。当它这样做时,它打开的文件应该被泄露。垃圾收集器检测到此泄漏。以下测试检查此行为:

def test_parse_bytes(self):
    make_xml_file(self.data, 'iso-8859-1', None)
    with support.check_warnings(('unclosed file', ResourceWarning)) :
        with self.assertRaises(SAXException):
            self.check_parse(TESTFN)
        gc.collect()

我的程序转换工具将此代码段更改为以下内容:

def test_parse_bytes(self):
    make_xml_file(self.data, 'iso-8859-1', None)
    with support.check_warnings(('unclosed file', ResourceWarning)) :
        t = self.assertRaises(SAXException)
        with t:
            self.check_parse(TESTFN)
        gc.collect()

根据我对Python的了解,这些片段应该完全相同。当我在调试器中单步执行时,我无法说出他们在做什么不同的事情。然而,不知何故,后一个片段会导致文件泄露,从而导致测试失败。为什么呢?

1 个答案:

答案 0 :(得分:2)

在第一个代码段中,调用self.assertRaises(SAXException)gc.collect()的结果超出了范围,因此它是垃圾并且保证会被收集;在第二个代码段中,引用t仍然在范围内,因此它不会。有一些从t到文件句柄的引用路径 - 可能它包含对引发的异常的引用,并且该异常包含对该文件的引用。因此,在gc.collect()被调用时,该文件不是垃圾,因此它不会自动关闭。外部with块然后检查未关闭的文件,并找到一个文件,虽然它是垃圾,如果垃圾收集器再次运行t超出范围,它将被关闭,但仍然是打开的。 / p>