ebo*_*yen 8 python garbage-collection python-2.7 python-3.x
我需要完成的事情:
给定二进制文件,以提供TextIOBaseAPI 的几种不同方式对其进行解码.理想情况下,这些后续文件可以在不需要明确跟踪其生命周期的情况下传递.
不幸的是,包含一个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
Run Code Online (Sandbox Code Playgroud)
我可以通过覆盖在Python 3中解决这个问题__del__(这对我的用例来说是一个合理的解决方案,因为我可以完全控制解码过程,我只需要在最后公开一个非常统一的API):
In [1]: import io
In [2]: class MyTextIOWrapper(io.TextIOWrapper):
...: def __del__(self):
...: print("I've been GC'ed")
...:
In [3]: def mangle2(x):
...: MyTextIOWrapper(x)
...:
In [4]: f2 = io.open('example', mode='rb')
In [5]: f2.closed
Out[5]: False
In [6]: mangle2(f2)
I've been GC'ed
In [7]: f2.closed
Out[7]: False
Run Code Online (Sandbox Code Playgroud)
但是这在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
Run Code Online (Sandbox Code Playgroud)
我花了一些时间盯着Python源代码,它在2.7和3.4之间看起来非常相似所以我不明白为什么__del__继承IOBase自在Python 2中不可覆盖(甚至可见dir),但似乎仍然得到执行.Python 3完全按预期工作.
有什么我能做的吗?
只需取下你的TextIOWrapper()对象让它被垃圾收集之前:
def mangle(x):
wrapper = io.TextIOWrapper(x)
wrapper.detach()
Run Code Online (Sandbox Code Playgroud)
该TextIOWrapper()对象仅关闭它所连接的流。如果您无法更改对象超出范围的代码,则只需在本地保留对该TextIOWrapper()对象的引用并在该点分离。
如果你必须继承TextIOWrapper(),那么只需要调用detach()的__del__钩:
class DetachingTextIOWrapper(io.TextIOWrapper):
def __del__(self):
self.detach()
Run Code Online (Sandbox Code Playgroud)