Weak attributes - cyclic references made easy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | import weakref
class weakattr(object):
"""
weakattr - a weakly-referenced attribute. When the attribute is no longer
referenced, it 'disappears' from the instance. Great for cyclic references.
"""
__slots__ = ["dict", "errmsg"]
def __init__(self, name = None):
self.dict = weakref.WeakValueDictionary()
if name:
self.errmsg = "%%r has no attribute named %r" % (name,)
else:
self.errmsg = "%r has no such attribute"
def __repr__(self):
return "<weakattr at 0x%08X>" % (id(self),)
def __get__(self, obj, cls):
if obj is None:
return self
try:
return self.dict[id(obj)]
except KeyError:
raise AttributeError(self.errmsg % (obj,))
def __set__(self, obj, value):
self.dict[id(obj)] = value
def __delete__(self, obj):
try:
del self.dict[id(obj)]
except KeyError:
raise AttributeError(self.errmsg % (obj,))
#
# example
#
>>> class x(object):
... next = weakattr()
... def __init__(self):
... self.next = self
... def __del__(self):
... print "g'bye"
...
>>>
>>> y = x()
>>> y.next
<__main__.x object at 0x009EFA50>
>>> del y
>>> gc.collect()
g'bye
0
|
When the attribute is no longer strongly-referenced, it just disappears. See http://sebulba.wikispaces.com/recipe+weakattr for more info.
Tags: extending
error in __delete__? I think "instance" in __delete__ should be "obj"
oops. fixed that. thanks :)
careful with id(obj)! Object addresses are reused. On OSX, the following program prints "uhh..." a few times.