Welcome, guest | Sign In | My Account | Store | Cart

Weak attributes - cyclic references made easy

Python, 55 lines
 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.

3 comments

Steven Bethard 17 years, 10 months ago  # | flag

error in __delete__? I think "instance" in __delete__ should be "obj"

tomer filiba (author) 17 years, 10 months ago  # | flag

oops. fixed that. thanks :)

Just van Rossum 17 years, 9 months ago  # | flag

careful with id(obj)! Object addresses are reused. On OSX, the following program prints "uhh..." a few times.

class Thing(object): pass
class Foo(object):
    weak = weakattr()
t = Thing()
for i in range(10):
    f = Foo()
    try:
        f.weak
    except AttributeError:
        print "good."
    else:
        print "uhh..."
    f.weak = t
Created by tomer filiba on Fri, 2 Jun 2006 (PSF)
Python recipes (4591)
tomer filiba's recipes (12)

Required Modules

  • (none specified)

Other Information and Tasks