2 Miscellaneous utilities |
2 Miscellaneous utilities |
3 """ |
3 """ |
4 |
4 |
5 import functools |
5 import functools |
6 |
6 |
7 class LazyProperty (property) : |
7 class LazyProperty (object) : |
8 """ |
8 """ |
9 Lazy-loaded cached properties. |
9 Lazy-loaded cached properties. |
10 |
10 |
11 This functions by overriding the class's property attribute with the actual value attribute in the instance's |
11 This functions by overriding the class's property attribute with the actual value attribute in the instance's |
12 dict, causing all future attribute lookups to return that directly. |
12 dict, causing all future attribute lookups to return that directly. |
|
13 |
|
14 >>> class Foo (object) : |
|
15 ... counter = 0 |
|
16 ... @lazy_load |
|
17 ... def foo (self) : |
|
18 ... self.counter += 1 |
|
19 ... return self.counter |
|
20 ... |
|
21 >>> foo = Foo(); foo.foo, foo.foo, foo.counter |
|
22 (1, 1, 1) |
|
23 |
13 """ |
24 """ |
14 |
25 |
15 def __init__ (self, func) : |
26 def __init__ (self, func) : |
16 """ |
27 """ |
17 Initialize with no value |
28 Initialize with no value |
18 """ |
29 """ |
19 |
|
20 super(LazyProperty, self).__init__(func) |
|
21 |
30 |
22 # the getter function |
31 # the getter function |
23 self.func = func |
32 self.func = func |
24 |
33 |
25 # the attribute name |
34 # the attribute name |
36 |
45 |
37 def store (self, obj, value) : |
46 def store (self, obj, value) : |
38 """ |
47 """ |
39 Store the cached value, overring ourself |
48 Store the cached value, overring ourself |
40 """ |
49 """ |
41 |
50 |
|
51 # print "[%x] %r.__dict__[%r] = %r" % (id(obj), obj, self.name, value) |
|
52 |
42 obj.__dict__[self.name] = value |
53 obj.__dict__[self.name] = value |
43 |
54 |
44 def __get__ (self, obj, owner) : |
55 def __get__ (self, obj, owner) : |
45 """ |
56 """ |
46 Generate the value, store it as the attribute and return it. |
57 Generate the value, store it as the attribute and return it. |
47 """ |
58 """ |
48 |
59 |
49 # compute value |
60 # compute value |
50 value = self.run(obj) |
61 value = self.run(obj) |
51 |
62 |
52 # store it |
63 # store it |
53 self.store(obj, value) |
64 self.store(obj, value) |
54 |
65 |
55 # return it |
66 # return it |
56 return value |
67 return value |
57 |
68 |
58 class LazyIteratorProperty (LazyProperty) : |
69 class LazyIteratorProperty (LazyProperty) : |
59 """ |
70 """ |
60 A lazy-loaded property that automatically converts an iterator/genexp into a list. |
71 A lazy-loaded property that automatically converts an iterator/genexp into a list. |
61 """ |
72 """ |
62 |
73 |
63 def run (self, obj) : |
74 def run (self, obj) : |
64 """ |
75 """ |
65 Wrap LazyProperty.run to return a list |
76 Wrap LazyProperty.run to return a list |
66 """ |
77 """ |
67 |
78 |
68 return list(super(LazyIteratorProperty, self).run(obj)) |
79 return list(self.func(obj)) |
69 |
80 |
70 lazy_load = LazyProperty |
81 lazy_load = LazyProperty |
71 lazy_load_iter = LazyIteratorProperty |
82 lazy_load_iter = LazyIteratorProperty |
72 |
83 |
|
84 # testing |
|
85 if __name__ == '__main__' : |
|
86 import doctest |
|
87 |
|
88 doctest.testmod() |
|
89 |