[Tutor] __weakref__ question
Mats Wichmann
mats at wichmann.us
Thu Jul 25 09:48:39 EDT 2019
On 7/24/19 1:57 PM, Sarah Hembree wrote:
> Can anyone provide some simple example/s or two or three of using weakref?
> I'm baffled and not seeing any documentation that is meaningful. My
> interest is to minimize memory usage (generally speaking, overall) and am
> wondering if this might help.
The answer is "maybe" and as a guess "probably not" going to give
signifgant memory savings - but it depends on circumstances.
It would help if you could describe a bit more of the scenario that
causes you to worry about memory usage.
I looked for documentation on __weakref__ since you said there didn't
seem to be anything meaningful and agree there's not much to go on - it
mostly seems to be something you have to fiddle with if you're using
__slots__. On the other hand, the weakref module, which is what you're
more likely to directly use, seems reasonably well documented.
There are sure to be people with more expertise here who can explain
this better... but the two prominent uses of weakref seem to be in
caching, and in avoiding reference loops (or rather avoiding problems
related to them). In the former case, if the things you put in your
cache are weak references, they can be garbage-collected by the Python
interpreter as needed, but before that happens you can refer to them.
Where it perhaps makes sense is where you have an object that is
expensive that you're doing some processing on, and you also add it,
with a weak reference to a list of recent objects. Once you're done...
well, I find that what I'm saying here is actually said better by the
documentation so I'll stop, just read there:
https://docs.python.org/3/library/weakref.html
The latter case, reference cycles, where things refer to each other in a
way that potentially nothing gets released, ought to eventually get
caught by the interpreter which has a garbage collection algorithm for
this, but you can speed things along by being explicit. Something like
this perhaps:
import ctypes
# Use ctypes to access unreachable object by memory address.
class PyObject(ctypes.Structure):
_fields_ = [("refcnt", ctypes.c_long)]
d1 = {}
d2 = {}
d1['obj2'] = d2
d2['obj1'] = d1
daddr = id(d1)
print("d1 ref count:", PyObject.from_address(daddr).refcnt)
## output: d1 ref count: 2
del d1, d2
print("d1 ref count:", PyObject.from_address(daddr).refcnt)
## output: d1 ref count: 2
## There's a non-zero refcount even though both dictionaries
## have been removed: d2 couldn't go away completely because
## it was still being referenced in d2, and d2 couldn't go away
## completely because it was still being referenced in d1,
## which couldn't go away because...
## We can change this by marking the values as weak references:
n1 = weakref.WeakValueDictionary()
n2 = weakref.WeakValueDictionary()
n1['obj2'] = n2
n2['obj1'] = n1
naddr = id(n1)
print("n1 ref count:", PyObject.from_address(naddr).refcnt)
## output: n1 ref count: 1
del n1, n2
print("n1 ref count:", PyObject.from_address(naddr).refcnt)
## output: n1 ref count: 0
## :: weakrefs don't contribute to the refcount.
Does this help at all?
More information about the Tutor
mailing list