Skip to content

Instantly share code, notes, and snippets.

@tiran
Created August 1, 2017 13:55
Show Gist options
  • Save tiran/da7d4c43d493c5aa7d7abc4d8a0678a6 to your computer and use it in GitHub Desktop.
Save tiran/da7d4c43d493c5aa7d7abc4d8a0678a6 to your computer and use it in GitHub Desktop.
Cached property and cached callable
import sys
import types
class cachedproperty(object):
__slots__ = ('fget', 'name', '__doc__')
def __init__(self, fget, doc=None):
self.fget = fget
self.name = fget.__name__ # python < 3.6
if doc is None:
doc = fget.__doc__
self.__doc__ = doc
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner=None):
if instance is None:
return self
value = self.fget(instance)
setattr(instance, self.name, value)
return value
class cachedcallable(object):
__slots__ = ('fget', 'name', '__doc__')
def __init__(self, fget, doc=None):
self.fget = fget
self.name = fget.__name__ # python < 3.6
if doc is None:
doc = fget.__doc__
self.__doc__ = doc
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner=None):
if instance is None:
return self
value = self.fget(instance)
def wrap(self):
return value
wrap.__doc__ = self.__doc__
if sys.version_info.major == 2:
wrap = types.MethodType(wrap, instance, type(instance))
else:
wrap = types.MethodType(wrap, instance)
setattr(instance, self.name, wrap)
return wrap
class Demo(object):
@cachedproperty
def answer(self):
print('answer called')
return 42
@cachedcallable
def get_answer(self):
print('get_answer called')
return 42
if __name__ == '__main__':
d = Demo()
print(d.answer)
print(d.answer)
print(d.answer)
print(d.get_answer())
print(d.get_answer())
print(d.get_answer())
print(d.get_answer)
@tiran
Copy link
Author

tiran commented Aug 1, 2017

answer called
42
42
42
get_answer called
42
42
42
<bound method cachedcallable.__get__.<locals>.wrap of <__main__.Demo object at 0x7fb89af32908>>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment