我想有一个从活动帧(FrameType
)对象到一些数据的字典映射。活动的意思是它在当前执行堆栈跟踪中。
但是,保留对frame对象的引用并不是一个好主意,因为这也会使帧保持非活动状态,并且很快就会耗尽内存,因为所有的引用都指向所有的局部变量。
自然的解决方案是使用对框架对象的弱引用,或者更具体地说是WeakKeyDictionary
。
但是,目前还不能创建一个指向框架对象的弱引用:
import weakref
import sys
f = sys._getframe()
weakref.ref(f)
收益率
TypeError: cannot create weak reference to 'frame' object
我认为这是一个CPython实现细节?
那么,有哪些选择呢?
我可能无论如何都可以创建引用,但当它们不再活跃时,请尽快清理它们。我如何检查一个框架对象是否处于活动状态?
这是一个疯狂的想法:如果你不能保持对框架的引用,让框架保持对你的引用。
class FrameDict:
def __init__(self):
self._data_by_frame_id = {}
def __setitem__(self, frame, data):
frame_id = id(frame)
# Make the frame hold a reference to a KeyDeleter, so when the frame
# dies, the KeyDeleter dies, and the frame is removed from the dict
deleter = KeyDeleter(self._data_by_frame_id, frame_id)
frame.f_locals[deleter] = deleter
self._data_by_frame_id[frame_id] = data
def __getitem__(self, frame):
frame_id = id(frame)
return self._data_by_frame_id[frame_id]
class KeyDeleter:
def __init__(self, mapping, key):
self.mapping = mapping
self.key = key
def __del__(self):
del self.mapping[self.key]
演示:
import inspect
def new_frame():
return inspect.currentframe()
frame_dict = FrameDict()
frame = new_frame()
frame_dict[frame] = 'foobar'
print(frame_dict[frame]) # foobar
del frame
print(frame_dict._data_by_frame_id) # {}