Skip to content

Instantly share code, notes, and snippets.

@laixintao
Created June 27, 2018 13:56
Show Gist options
  • Save laixintao/f1114d964c19679c973c2c3c3f1fa8ba to your computer and use it in GitHub Desktop.
Save laixintao/f1114d964c19679c973c2c3c3f1fa8ba to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
import time
# copy out from django
# https://docs.djangoproject.com/zh-hans/2.0/_modules/django/utils/functional/#cached_property
class cached_property:
"""
Decorator that converts a method with a single self argument into a
property cached on the instance.
Optional ``name`` argument allows you to make cached properties of other
methods. (e.g. url = cached_property(get_absolute_url, name='url') )
"""
def __init__(self, func, name=None):
self.func = func
self.__doc__ = getattr(func, "__doc__")
self.name = name or func.__name__
def __get__(self, instance, cls=None):
"""
Call the function and put the return value in instance.__dict__ so that
subsequent attribute access on the instance returns the cached value
instead of calling cached_property.__get__().
"""
if instance is None:
return self
res = instance.__dict__[self.name] = self.func(instance)
return res
class Foo:
@cached_property
def foo(self):
return time.time()
print(dir(Foo))
print(type(Foo.foo))
f = Foo()
print(f.foo)
time.sleep(0.03)
print(f.foo)
@laixintao
Copy link
Author

# delete L27 and L28
➜ [takachiho] playground git:(master) ✗ python test_cached_property.py
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'foo']
Traceback (most recent call last):
  File "test_cached_property.py", line 40, in <module>
    print(type(Foo.foo))
  File "test_cached_property.py", line 29, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
AttributeError: 'NoneType' object has no attribute '__dict__'

# original code
➜ [takachiho] playground git:(master) ✗ python test_cached_property.py
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'foo']
<class '__main__.cached_property'>
1530107803.403837
1530107803.403837
➜ [takachiho] playground git:(master) ✗

@laixintao
Copy link
Author

laixintao commented Jun 27, 2018

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