Skip to content

Commit c855a88

Browse files
move almost all __dict__ magic into placeholder
1 parent 52967a1 commit c855a88

File tree

1 file changed

+14
-16
lines changed

1 file changed

+14
-16
lines changed

asyncstdlib/functools.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,25 @@ def __repr__(self) -> str:
6666
return f"{self.__class__.__name__}({self.value!r})"
6767

6868

69-
class _FutureCachedValue(Generic[R, T]):
70-
"""A placeholder object to control concurrent access to a cached awaitable value.
69+
class _FutureCachedPropertyValue(Generic[R, T]):
70+
"""
71+
A placeholder object to control concurrent access to a cached awaitable value
7172
7273
When given a lock to coordinate access, only the first task to await on a
7374
cached property triggers the underlying coroutine. Once a value has been
7475
produced, all tasks are unblocked and given the same, single value.
75-
7676
"""
7777

78-
__slots__ = ("_get_attribute", "_instance", "_name", "_lock")
78+
__slots__ = ("_func", "_instance", "_name", "_lock")
7979

8080
def __init__(
8181
self,
82-
get_attribute: Callable[[T], Coroutine[Any, Any, R]],
82+
func: Callable[[T], Awaitable[R]],
8383
instance: T,
8484
name: str,
8585
lock: AsyncContextManager[Any],
8686
):
87-
self._get_attribute = get_attribute
87+
self._func = func
8888
self._instance = instance
8989
self._name = name
9090
self._lock = lock
@@ -116,12 +116,17 @@ async def _await_impl(self) -> R:
116116
# the instance attribute is still this placeholder, and we
117117
# hold the lock. Start the getter to store the value on the
118118
# instance and return the value.
119-
return await self._get_attribute(self._instance)
119+
return await self._get_attribute()
120120

121121
# another task produced a value, or the instance.__dict__ object was
122122
# deleted in the interim.
123123
return await stored
124124

125+
async def _get_attribute(self) -> R:
126+
value = await self._func(self._instance)
127+
self._instance.__dict__[self._name] = AwaitableValue(value)
128+
return value
129+
125130
def __repr__(self) -> str:
126131
return (
127132
f"<{type(self).__name__} for '{type(self._instance).__name__}."
@@ -176,19 +181,12 @@ def __get__(
176181
# on this instance. It takes care of coordinating between different
177182
# tasks awaiting on the placeholder until the cached value has been
178183
# produced.
179-
wrapper = _FutureCachedValue(
180-
self._get_attribute, instance, name, self._asynccontextmanager_type()
184+
wrapper = _FutureCachedPropertyValue(
185+
self.func, instance, name, self._asynccontextmanager_type()
181186
)
182187
cache[name] = wrapper
183188
return wrapper
184189

185-
async def _get_attribute(self, instance: T) -> R:
186-
value = await self.func(instance)
187-
name = self.attrname
188-
assert name is not None # enforced in __get__
189-
instance.__dict__[name] = AwaitableValue(value)
190-
return value
191-
192190

193191
def cached_property(
194192
type_or_getter: Union[Type[AsyncContextManager[Any]], Callable[[T], Awaitable[R]]],

0 commit comments

Comments
 (0)