1 # -*- coding: utf-8 -*-
3 __author__
= 'Daniel Greenfeld'
4 __email__
= 'pydanny@gmail.com'
16 class cached_property(object):
18 A property that is only computed once per instance and then replaces itself
19 with an ordinary attribute. Deleting the attribute resets the property.
20 Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76
23 def __init__(self
, func
):
24 self
.__doc
__ = getattr(func
, '__doc__')
27 def __get__(self
, obj
, cls
):
30 if asyncio
and asyncio
.iscoroutinefunction(self
.func
):
31 return self
._wrap
_in
_coroutine
(obj
)
32 value
= obj
.__dict
__[self
.func
.__name
__] = self
.func(obj
)
35 def _wrap_in_coroutine(self
, obj
):
38 future
= asyncio
.ensure_future(self
.func(obj
))
39 obj
.__dict
__[self
.func
.__name
__] = future
44 class threaded_cached_property(object):
46 A cached_property version for use in environments where multiple threads
47 might concurrently try to access the property.
50 def __init__(self
, func
):
51 self
.__doc
__ = getattr(func
, '__doc__')
53 self
.lock
= threading
.RLock()
55 def __get__(self
, obj
, cls
):
59 obj_dict
= obj
.__dict
__
60 name
= self
.func
.__name
__
63 # check if the value was computed before the lock was acquired
66 # if not, do the calculation and release the lock
67 return obj_dict
.setdefault(name
, self
.func(obj
))
70 class cached_property_with_ttl(object):
72 A property that is only computed once per instance and then replaces itself
73 with an ordinary attribute. Setting the ttl to a number expresses how long
74 the property will last before being timed out.
77 def __init__(self
, ttl
=None):
84 self
._prepare
_func
(func
)
86 def __call__(self
, func
):
87 self
._prepare
_func
(func
)
90 def __get__(self
, obj
, cls
):
95 obj_dict
= obj
.__dict
__
98 value
, last_updated
= obj_dict
[name
]
102 ttl_expired
= self
.ttl
and self
.ttl
< now
- last_updated
106 value
= self
.func(obj
)
107 obj_dict
[name
] = (value
, now
)
110 def __delete__(self
, obj
):
111 obj
.__dict
__.pop(self
.__name
__, None)
113 def __set__(self
, obj
, value
):
114 obj
.__dict
__[self
.__name
__] = (value
, time())
116 def _prepare_func(self
, func
):
119 self
.__doc
__ = func
.__doc
__
120 self
.__name
__ = func
.__name
__
121 self
.__module
__ = func
.__module
__
123 # Aliases to make cached_property_with_ttl easier to use
124 cached_property_ttl
= cached_property_with_ttl
125 timed_cached_property
= cached_property_with_ttl
128 class threaded_cached_property_with_ttl(cached_property_with_ttl
):
130 A cached_property version for use in environments where multiple threads
131 might concurrently try to access the property.
134 def __init__(self
, ttl
=None):
135 super(threaded_cached_property_with_ttl
, self
).__init
__(ttl
)
136 self
.lock
= threading
.RLock()
138 def __get__(self
, obj
, cls
):
140 return super(threaded_cached_property_with_ttl
, self
).__get
__(obj
,
143 # Alias to make threaded_cached_property_with_ttl easier to use
144 threaded_cached_property_ttl
= threaded_cached_property_with_ttl
145 timed_threaded_cached_property
= threaded_cached_property_with_ttl