我必须做 StringIO.close() 吗?

Posted

技术标签:

【中文标题】我必须做 StringIO.close() 吗?【英文标题】:Do I have to do StringIO.close()? 【发布时间】:2012-03-31 21:57:33 【问题描述】:

一些代码:

import cStringIO

def f():
    buffer = cStringIO.StringIO()
    buffer.write('something')
    return buffer.getvalue()

documentation 说:

StringIO.close():释放内存缓冲区。尝试进一步做 使用关闭的 StringIO 对象的操作将引发 ValueError。

我必须做buffer.close(),否则它会在缓冲区超出范围并被垃圾收集时自动发生?

更新:

我做了一个测试:

import StringIO, weakref

def handler(ref):
    print 'Buffer died!'

def f():
    buffer = StringIO.StringIO()
    ref = weakref.ref(buffer, handler)
    buffer.write('something')
    return buffer.getvalue()

print 'before f()'
f()
print 'after f()'

结果:

vic@wic:~/projects$ python test.py 
before f()
Buffer died!
after f()
vic@wic:~/projects$

【问题讨论】:

为什么不打印 f() 而不是直接打印 f()? 【参考方案1】:

一般还是调用close()或者使用with语句比较好,因为在特殊情况下可能会出现一些意想不到的行为。例如,expat-IncrementalParser 似乎希望文件被关闭,或者在某些极少数情况下发生超时之前它不会返回已解析 xml 的最后一点。

但是对于为您处理关闭的with-statement,您必须使用io-Modules 中的StringIO 类,如Ivc 的评论中所述。

这是我们通过手动关闭 StringIO 解决的一些遗留 sax 解析器脚本中的一个主要问题。

“范围外”关闭不起作用。它只是等待超时限制。

【讨论】:

除了注意 Py2 中的 StringIO 和 cStringIO 没有实现上下文管理器协议 - 因此,要在 with 语句中使用它,您需要执行 with contextlib.closing(StringIO()) as buffer:。另一方面,Py3 的io.StringIO可以直接用在with 语句中。 io.StringIO 确实实现了上下文管理器协议,但不是 2.6 之前的协议,请参阅:docs.python.org/release/2.6.7/library/…` 啊,我没有意识到io 模块存在那么久。感谢您的指点。但是,OP 中使用的 StringIO.StringIOcStringIO.StringIO 模块仍然没有。实际上,我有点惊讶它们在 2.6/2.7 中没有被标记为已弃用,而且 2.7 文档中甚至没有通常的注释说“这些在 3.x 中不再存在”。 你说得对,坦率地说我并没有真正注意这一事实,OP 没有使用 io 模块!感谢您指出了这一点! ;-)【参考方案2】:

来源:

class StringIO:
    ...
    def close(self):
        """Free the memory buffer.
        """
        if not self.closed:
            self.closed = True
            del self.buf, self.pos

所以StringIO.close 只是释放内存缓冲区删除对StringIO.bufStringIO.pos 的引用。但是如果self被垃圾回收,它的属性也会被垃圾回收,效果和StringIO.close一样。

【讨论】:

【参考方案3】:

StringIO.close() 只是为接受类似文件并最终尝试关闭它们的例程提供便利。自己不需要这样做。

【讨论】:

这不是方便,而是必需。如果没有它,关闭类似文件的对象的代码将会中断。 @Maxim:该代码是必需的。这对客户来说很方便。【参考方案4】:

我最终使用try 块来处理它。

import cStringIO

def f():
    buffer = cStringIO.StringIO()
    try:
        buffer.write('something')
        return buffer.getvalue()
    finally:
        buffer.close()

【讨论】:

或者,使用来自contextlib.closingwith closing()

以上是关于我必须做 StringIO.close() 吗?的主要内容,如果未能解决你的问题,请参考以下文章

winfrom算是.net开发吗?请指教!

执行获取请求时,我必须在核心数据中提供 NSSortDescriptor 吗?

你必须弄乱 Rails 的“routes.rb”文件吗?

我必须关闭()每个 EntityManager 吗?

做嵌入式的必须学Android吗

我必须使用目录的本地化版本吗?