aio-libs / aio-libs/propcache

add an addtional class that can define a custom cache attribute

オープン
#200 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
enhancement
主要言語
Python
スター
36
フォーク
23
平均マージ
2時間 24分
マージ済み PR(30日)
10

説明

### Is your feature request related to a problem?

I wanted to add custom cache slot locations so that users could have something a bit more beginner friendly to work with.

### Describe the solution you'd like

I had a concept already written for this to exist but I wanted to try adding in a 2 new classes that could help users build caches in different defined slots instead of being limited to only `_cache` and `__dict__`
```py
class under_cached_slot_property(Generic[_T]):
"""Use as a class method decorator.

It operates almost the exact same was as under_cached_property but allow
for a custom slot instead of "_cache" to be used.
"""

def __init__(self, wrapped: Callable[[Any], _T], cache_name:str) -> None:
self.wrapped = wrapped
self.__doc__ = wrapped.__doc__
self.name = wrapped.__name__
self.cache_name = cache_name

@overload
def __get__(self, inst: None, owner: Optional[type[object]] = None) -> Self: ...

@overload
def __get__(
self, inst: Any, owner: Optional[type[object]] = None
) -> _T: ...

def __get__(
self, inst: Optional[Any], owner: Optional[type[object]] = None
) -> Union[_T, Self]:
_cache = getattr(inst, self.cache_name) # type: dict[str, Any]
if inst is None:
return self
try:
return _cache[self.name] # type: ignore[no-any-return]
except KeyError:
val = self.wrapped(inst)
_cache[self.name] = val
return val

def __set__(self, inst: Any, value: _T) -> None:
raise AttributeError("cached property is read-only")

class under_cache_name:
"""Uses a provided cache to create a `under_cached_slot_property` with. a given name"""
def __init__(self, name:str) -> None:
self.name = name

def __call__(self, wrapped: Callable[..., _T]) -> under_cached_attribute_property[_T]:
return under_cached_attribute_property(wrapped)

```

How it would work is pretty simplistic to understand also. The reason the second class is not a function is to
make it faster for cython to compute. A little dumb example will suffice with what I am trying to explain.
```py
from dataclasses import dataclass, field

reify = under_cached_name("_my_cache")

@dataclass(slots=True) # this will work with __slots__.
class MyTool:
i: int
_my_cache: dict[str, Any] = field(default_factory=dict, init=Fasle)

@reify
def cached_item(self) -> int:
return self.i + 10
```

### Describe alternatives you've considered

I'm willing to maintain this new object myself if rejected and put it into it's own little library along with cython optimizations included but also have it include it's own pure python fallback module.

### Additional context

_No response_

### Code of Conduct

- [x] I agree to follow the aio-libs Code of Conduct

コントリビューションガイド

コントリビューションガイドを開く

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。