weakref (WeakKeyDictionary) 到框架 (FrameType) 对象

weakref (WeakKeyDictionary) to frame (FrameType) objects

我想要一个从活动帧 (FrameType) 对象到某些数据的字典映射。活动意味着它在当前执行堆栈跟踪中。

但是,保留对框架对象的引用不是一个好主意,因为这也会保留非活动框架,并且由于对所有局部变量的所有引用,很快就会耗尽内存。

自然的解决方案是对框架对象使用弱引用,或者更具体地说 WeakKeyDictionary

但是,目前无法为框架对象创建弱引用:

import weakref
import sys

f = sys._getframe()
weakref.ref(f)

产量

TypeError: cannot create weak reference to 'frame' object

我假设这是 CPython 实现细节?

那么,有哪些选择呢?

我可能无论如何都可以创建引用,但是当它们不再活动时,请尝试尽快清理它们。 How do I actually check if a frame object is active?

这是一个疯狂的想法:如果您不能保存对框架的引用,请让框架保存对您的引用。

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)  # {}