我正在尝试理解Python weakref模块及其用例,因此我有以下设置:
import gc, weakref
class obj(object):
def __init__(self, val=None):
self._s = "Sample" if not val else " ".join(["Sample:", str(val)])
def sample(self):
return self._s
ol = [obj(x) for x in range(1,4)]
o1 = obj(1)
o2 = obj(2)
o3 = obj(3)
wdict1 = weakref.WeakValueDictionary({k:ol[k-1] for k in range(1,4)})
wdict2 = weakref.WeakValueDictionary()
wdict2[1] = o1
wdict2[2] = o2
wdict2[3] = o3在运行测试之后,我可以清楚地看到,WeakValueDictionary在某种程度上保留了所有的值,尽管我已经显式地调用了gc.collect()。据我理解,并在下面的回答中解释了,调用gc.collect()应该删除所有弱引用的值。
In [2]: wdict1.items()
Out[2]:
[(1, <__main__.obj at 0x7fea09c0be90>),
(2, <__main__.obj at 0x7fea09c0bf10>),
(3, <__main__.obj at 0x7fea09c0bf50>)]
In [3]: wdict2.items()
Out[3]:
[(1, <__main__.obj at 0x7fea09c51790>),
(2, <__main__.obj at 0x7fea09c0bed0>),
(3, <__main__.obj at 0x7fea09c0bf90>)]
In [4]: del ol[0]
In [5]: del o1
In [6]: gc.collect()
Out[6]: 64
In [7]: wdict1.items()
Out[7]:
[(1, <__main__.obj at 0x7fea09c0be90>),
(2, <__main__.obj at 0x7fea09c0bf10>),
(3, <__main__.obj at 0x7fea09c0bf50>)]
In [8]: wdict2.items()
Out[8]:
[(1, <__main__.obj at 0x7fea09c51790>),
(2, <__main__.obj at 0x7fea09c0bed0>),
(3, <__main__.obj at 0x7fea09c0bf90>)]
In [9]: del ol[0]
In [10]: del o2
In [11]: gc.collect()
Out[11]: 0
In [12]: wdict1.items()
Out[12]:
[(1, <__main__.obj at 0x7fea09c0be90>),
(2, <__main__.obj at 0x7fea09c0bf10>),
(3, <__main__.obj at 0x7fea09c0bf50>)]
In [13]: wdict2.items()
Out[13]:
[(1, <__main__.obj at 0x7fea09c51790>),
(2, <__main__.obj at 0x7fea09c0bed0>),
(3, <__main__.obj at 0x7fea09c0bf90>)]
In [14]: weakref.getweakrefs(ol[0])
Out[14]: [<weakref at 0x7fea0ab05470; to 'obj' at 0x7fea09c0bf50>]
In [15]: weakref.getweakrefs(o3)
Out[15]: [<weakref at 0x7fea09c060b0; to 'obj' at 0x7fea09c0bf90>]
In [16]: wdict1[1].sample()
Out[16]: 'Sample: 1'
In [17]: wdict2[2].sample()
Out[17]: 'Sample: 2'我的代码有什么问题,为什么所有弱引用的值都保持不变?
发布于 2015-10-07 10:38:15
问题是IPython使用以下方法保存对对象的引用-
来自文档 -
输入和输出历史记录保存在名为
In和Out的变量中,这些变量由提示符数字(如In[4])键决定。输出历史中的最后三个对象也保存在变量_、__和___中。
实际上,您可以尝试运行Out[2],并看到它将是对wdict1.items()结果的引用(如果在2提示符中,您按照您在示例中所给出的方式运行了该语句)。
IPython很可能保存了大量对对象的此类引用,因此当您删除ol[0]或o1之类的名称时,然后执行gc.collect。它实际上并不收集对象,因为仍然存在对对象的引用(在_、__或___或Out[num]中)。
我能想到两种解决方案-
%xdel魔术命令删除引用,比如%xdel ol[0],而不是del ol[0]。这将导致IPython清除它保存的所有引用。基于文件-删除一个变量,尝试从IPython的机器引用它的任何地方清除它。
https://stackoverflow.com/questions/32989283
复制相似问题