def cache(descriptor=None, *, store: IStore = None):
if descriptor is None:<EOL><INDENT>return functools.partial(cache, store=store)<EOL><DEDENT>hasattrs = {<EOL>'<STR_LIT>': hasattr(descriptor, '<STR_LIT>'),<EOL>'<STR_LIT>': hasattr(descriptor, '<STR_LIT>'),<EOL>'<STR_LIT>': hasattr(descriptor, '<STR_LIT>')<EOL>}<EOL>descriptor_name = get_descriptor_name(descriptor)<EOL>class CacheDescriptor(ICacheDescriptor):<EOL><INDENT>def __init__(self):<EOL><INDENT>if descriptor_name is not None:<EOL><INDENT>self.__name__ = descriptor_name<EOL><DEDENT><DEDENT><DEDENT>cache_descriptor = CacheDescriptor()<EOL>if store is None:<EOL><INDENT>store = FieldStore(cache_descriptor)<EOL><DEDENT>elif not isinstance(store, IStore):<EOL><INDENT>raise TypeError(f'<STR_LIT>')<EOL><DEDENT>if hasattrs['<STR_LIT>']:<EOL><INDENT>def get(self, obj, objtype):<EOL><INDENT>if obj is None:<EOL><INDENT>return descriptor.__get__(obj, objtype)<EOL><DEDENT>value = store.get(self, obj, defval=NOVALUE)<EOL>if value is NOVALUE:<EOL><INDENT>value = descriptor.__get__(obj, objtype)<EOL>store.set(self, obj, value)<EOL><DEDENT>return value<EOL><DEDENT>CacheDescriptor.__get__ = get<EOL><DEDENT>if hasattrs['<STR_LIT>']:<EOL><INDENT>def set(self, obj, value):<EOL><INDENT>store.pop(self, obj)<EOL>descriptor.__set__(obj, value)<EOL><DEDENT>CacheDescriptor.__set__ = set<EOL><DEDENT>if hasattrs['<STR_LIT>']:<EOL><INDENT>def delete(self, obj):<EOL><INDENT>store.pop(self, obj)<EOL>descriptor.__delete__(obj)<EOL><DEDENT>CacheDescriptor.__delete__ = delete<EOL><DEDENT>return cache_descriptor<EOL>
usage:

``` py
@cache
@property
def name(self): pass
```