Receita: Weak List
O módulo weakref contém duas implementações de weakdicts, dicionários que não aumentam a contagem de referências dos objetos: um que usa weakrefs para valores e o outro para chaves. Essa receita traz a implementação de uma weaklist, que você pode usar em situações que precise armazenar objetos sem aumentar sua contagem de referências. Caches de objetos e listas de clientes de um servidor são um bom exemplo.
Código
1 import weakref
2
3
4 class WeakList(list):
5
6 def __add__(self, y):
7 l = [i() for i in self]
8 return list.__add__(l, y)
9
10 def __contains__(self, y):
11 ref = weakref.ref(y)
12 return list.__contains__(self, ref)
13
14 def __eq__(self, y):
15 l = [i() for i in self]
16 return list.__eq__(l, y)
17
18 def __repr__(self):
19 return "<WeakList at %s>" % id(self)
20
21 def __getitem__(self, i):
22 ref = list.__getitem__(self, i)
23 return ref()
24
25 def __setitem__(self, i, y):
26 ref = weakref.ref(y)
27 list.__setitem__(self, i, ref)
28
29 def append(self, y):
30 list.append(self, weakref.ref(y))
31
32 def count(self, y):
33 l = [x() for x in self]
34 return list.count(l, y)
35
36 def extend(self, y):
37 for o in y:
38 list.append(self, weakref.ref(o))
39
40 def index(self, y):
41 ref = weakref.ref(y)
42 return list.index(self, ref)
43
44 def insert(self, i, y):
45 ref = weakref.ref(y)
46 list.insert(self, i, ref)
47
48 def pop(self):
49 ref = list.pop(self)
50 return ref()
51
52 def remove(self, y):
53 ref = weakref.ref(y)
54 list.remove(self, ref)
55
56 def sort(self, cmpfunc=None):
57
58 if cmpfunc is None:
59 def n_cmpfunc(x, y):
60 if x() > y(): return 1
61 if x() == y(): return 0
62 if x() < y(): return -1
63
64 else:
65 def n_cmpfunc(x, y):
66 return cmpfunc(x(), y())
67
68 list.sort(self, n_cmpfunc)
Teste
1 import unittest
2 import weaklist
3 import weakref
4 import random
5
6
7 class Object(object):
8 pass
9
10 class TestWeakList(unittest.TestCase):
11 def setUp(self):
12 self.list = weaklist.WeakList()
13
14 def tearDown(self):
15 del self.list
16
17 def testAttributes(self):
18 for attr in dir(list):
19 self.assert_(attr in dir(self.list))
20
21 def testSetItem(self):
22 o = Object()
23 list.append(self.list, None)
24 self.list[0] = o
25 self.assert_(list.__getitem__(self.list, 0)() is o)
26
27 def testGetItem(self):
28 o = Object()
29 list.append(self.list, weakref.ref(o))
30 self.assert_(self.list[0] is o)
31
32 def testDelItem(self):
33 o = Object()
34 ref = weakref.ref(o)
35 list.append(self.list, ref)
36 del self.list[0]
37 self.assert_(not list.__contains__(self.list, ref))
38
39 def testAppend(self):
40 o = Object()
41 self.list.append(o)
42 self.assert_(list.pop(self.list)() is o)
43
44 def testCount(self):
45 a = Object()
46 b = Object()
47 c = Object()
48 y = {3:a, 5:b, 8:c}
49
50 for n, o in y.items():
51 for x in range(n):
52 list.append(self.list, weakref.ref(o))
53
54 for n, o in y.items():
55 x = self.list.count(o)
56 self.assertEqual(x, n)
57
58 def testExtend(self):
59 l = [Object() for x in range(10)]
60 o = Object()
61 list.append(self.list, weakref.ref(o))
62 self.list.extend(l)
63 self.assertEqual(list.__len__(self.list), 11)
64 for x in range(10):
65 self.assert_(list.pop(self.list)() is l.pop())
66 self.assert_(list.pop(self.list)() is o)
67
68 def testIndex(self):
69 l = [weakref.ref(Object()) for x in range(10)]
70 o = Object()
71 ref = weakref.ref(o)
72 list.extend(self.list, l)
73 list.__setitem__(self.list, 4, ref)
74 self.assertEqual(self.list.index(o), 4)
75
76 def testInsert(self):
77 l = [weakref.ref(Object()) for x in range(10)]
78 list.extend(self.list, l)
79 o = Object()
80 self.list.insert(5, o)
81 self.assert_(list.__getitem__(self.list, 5)() is o)
82
83 def testPop(self):
84 o = Object()
85 list.append(self.list, weakref.ref(o))
86 self.assert_(self.list.pop() is o)
87
88 def testRemove(self):
89 l = [weakref.ref(Object()) for x in range(10)]
90 list.extend(self.list, l)
91 o = Object()
92 ref = weakref.ref(o)
93 list.insert(self.list, 7, ref)
94 self.list.remove(o)
95 self.assert_(not list.__contains__(self.list, ref))
96
97 def testReverse(self):
98 a, b, c = Object(), Object(), Object()
99 for o in a, b, c:
100 list.append(self.list, weakref.ref(o))
101 self.list.reverse()
102 for o in a, b, c:
103 self.assert_(list.pop(self.list)() is o)
104
105 def testSortWithFunc(self):
106 l = []
107 f = []
108 for x in range(10):
109 o = Object()
110 o.i = x
111 f.append(o)
112 l.append(weakref.ref(o))
113 random.shuffle(l)
114
115 list.extend(self.list, l)
116
117 def cmpfunc(x, y):
118 if x.i > y.i: return 1
119 if x.i == y.i: return 0
120 if x.i < y.i: return -1
121
122 self.list.sort(cmpfunc)
123 for x in range(10):
124 self.assert_(list.pop(self.list)() is f.pop())
125
126 def testSortWithoutFunc(self):
127
128 class Object(object):
129 def __init__(self, i):
130 self.i = i
131
132 def __lt__(self, other):
133 return self.i < other.i
134
135 def __le__(self, other):
136 return self.i <= other.i
137
138 def __eq__(self, other):
139 return self.i == other.i
140
141 def __ne__(self, other):
142 return self.i != other.i
143
144 def __gt__(self, other):
145 return self.i > other.i
146
147 def __ge__(self, other):
148 return self.i >= other.i
149
150 l = []
151 f = []
152 for x in range(10):
153 o = Object(x)
154 f.append(o)
155 l.append(weakref.ref(o))
156 random.shuffle(l)
157
158 list.extend(self.list, l)
159
160 self.list.sort()
161 for x in range(10):
162 self.assert_(list.pop(self.list)() is f.pop())
163
164 def testAdd(self):
165 o = Object()
166 list.append(self.list, weakref.ref(o))
167 l = [1, 2]
168 f = self.list + l
169 self.assert_(o in f)
170
171 def testContains(self):
172 o = Object()
173 list.append(self.list, weakref.ref(o))
174 self.assert_(o in self.list)
175
176 def testDelSlice(self):
177 l = [Object() for x in range(10)]
178 f = [weakref.ref(o) for o in l]
179
180 list.extend(self.list, f)
181 del l[2:6]
182 del self.list[2:6]
183 while l:
184 self.assert_(l.pop() is list.pop(self.list)())
185
186 def testEq(self):
187 l = [Object(), Object(), Object()]
188 for o in l:
189 list.append(self.list, weakref.ref(o))
190 self.assert_(self.list == l)
191 self.assert_(l == self.list)
192
193
194 if __name__ == "__main__":
195 unittest.main()
Volta para CookBook.