<p>编辑:</p>
<p><a href="https://stackoverflow.com/a/54421867/579416">Just call ^{<cd1>} first, thanks martijn-pieters!</a></p>
<hr/>
<p>事实证明,对于Python2.7中调用<code>close</code>的解构器,基本上什么也做不了。这是硬编码到C代码中的。相反,我们可以修改<code>close</code>,这样当<code>__del__</code>发生时它不会关闭缓冲区(在C代码中,<code>__del__</code>将在<code>_PyIOBase_finalize</code>之前执行,给我们一个改变<code>close</code>行为的机会)。这使<code>close</code>按预期工作,而不让GC关闭缓冲区。在</p>
<pre><code>class SaneTextIOWrapper(io.TextIOWrapper):
def __init__(self, *args, **kwargs):
self._should_close_buffer = True
super(SaneTextIOWrapper, self).__init__(*args, **kwargs)
def __del__(self):
# Accept the inevitability of the buffer being closed by the destructor
# because of this line in Python 2.7:
# https://github.com/python/cpython/blob/2.7/Modules/_io/iobase.c#L221
self._should_close_buffer = False
self.close() # Actually close for Python 3 because it is an override.
# We can't call super because Python 2 doesn't actually
# have a `__del__` method for IOBase (hence this
# workaround). Close is idempotent so it won't matter
# that Python 2 will end up calling this twice
def close(self):
# We can't stop Python 2.7 from calling close in the deconstructor
# so instead we can prevent the buffer from being closed with a flag.
# Based on:
# https://github.com/python/cpython/blob/2.7/Lib/_pyio.py#L1586
# https://github.com/python/cpython/blob/3.4/Lib/_pyio.py#L1615
if self.buffer is not None and not self.closed:
try:
self.flush()
finally:
if self._should_close_buffer:
self.buffer.close()
</code></pre>
<p>我之前的解决方案使用了<code>_pyio.TextIOWrapper</code>,这比上面的要慢,因为它是用Python编写的,而不是用C编写的</p>
<p>它只需要用一个noop覆盖{<cd4>},这个noop也可以在Py2/3中工作。在</p>