我需要完成的任务:
给定一个二进制文件,用两种不同的方式解码,提供一个TextIOBase
API。理想情况下,这些后续文件可以被传递,而不需要显式地跟踪它们的寿命。在
不幸的是,包装BufferedReader
将
导致当TextIOWrapper
超出范围时,该读卡器被关闭。在
下面是一个简单的演示:
In [1]: import io
In [2]: def mangle(x):
...: io.TextIOWrapper(x) # Will get GCed causing __del__ to call close
...:
In [3]: f = io.open('example', mode='rb')
In [4]: f.closed
Out[4]: False
In [5]: mangle(f)
In [6]: f.closed
Out[6]: True
我可以在python3中通过重写__del__
来解决这个问题(对于我的用例来说这是一个合理的解决方案,因为我可以完全控制解码过程,我只需要在最后公开一个非常统一的API):
但是,这在Python 2中不起作用:
In [7]: class MyTextIOWrapper(io.TextIOWrapper):
...: def __del__(self):
...: print("I've been GC'ed")
...:
In [8]: def mangle2(x):
...: MyTextIOWrapper(x)
...:
In [9]: f2 = io.open('example', mode='rb')
In [10]: f2.closed
Out[10]: False
In [11]: mangle2(f2)
I've been GC'ed
In [12]: f2.closed
Out[12]: True
我花了一点时间看Python源代码,它在2.7和3.4之间看起来非常相似,所以我不明白为什么从IOBase
继承的__del__
在python2中不可重写(甚至在dir
中可见),但似乎仍然可以执行。Python3与预期完全一致。在
我能做些什么吗?在
编辑:
Just call ^{} first, thanks martijn-pieters!
事实证明,对于Python2.7中调用
close
的解构器,基本上什么也做不了。这是硬编码到C代码中的。相反,我们可以修改close
,这样当__del__
发生时它不会关闭缓冲区(在C代码中,__del__
将在_PyIOBase_finalize
之前执行,给我们一个改变close
行为的机会)。这使close
按预期工作,而不让GC关闭缓冲区。在我之前的解决方案使用了
_pyio.TextIOWrapper
,这比上面的要慢,因为它是用Python编写的,而不是用C编写的它只需要用一个noop覆盖{},这个noop也可以在Py2/3中工作。在
一个简单的解决方案是从函数返回变量并将其存储在脚本范围内,这样在脚本结束或对它的引用发生更改之前,它不会被垃圾回收。但可能还有其他优雅的解决方案。在
只需将
TextIOWrapper()
对象分离,然后将其垃圾回收:TextIOWrapper()
对象只关闭它所附加到的流。如果不能更改对象超出范围的代码,那么只需在本地保留对TextIOWrapper()
对象的引用并在该点分离。在如果必须子类
^{pr2}$TextIOWrapper()
,那么只要在__del__
钩子中调用detach()
:相关问题 更多 >
编程相关推荐