Fixed #22691 -- Added aliasing to cached_property.

This commit is contained in:
Curtis 2014-05-24 20:29:31 +10:00 committed by Tim Graham
parent 34ba86706f
commit 71461b14ab
3 changed files with 34 additions and 3 deletions

View File

@ -45,14 +45,18 @@ class cached_property(object):
""" """
Decorator that converts a method with a single self argument into a Decorator that converts a method with a single self argument into a
property cached on the instance. 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): def __init__(self, func, name=None):
self.func = func self.func = func
self.name = name or func.__name__
def __get__(self, instance, type=None): def __get__(self, instance, type=None):
if instance is None: if instance is None:
return self return self
res = instance.__dict__[self.func.__name__] = self.func(instance) res = instance.__dict__[self.name] = self.func(instance)
return res return res

View File

@ -423,7 +423,7 @@ Atom1Feed
.. module:: django.utils.functional .. module:: django.utils.functional
:synopsis: Functional programming tools. :synopsis: Functional programming tools.
.. class:: cached_property(object) .. class:: cached_property(object, name)
The ``@cached_property`` decorator caches the result of a method with a The ``@cached_property`` decorator caches the result of a method with a
single ``self`` argument as a property. The cached result will persist single ``self`` argument as a property. The cached result will persist
@ -483,6 +483,24 @@ Atom1Feed
database by some other process in the brief interval between subsequent database by some other process in the brief interval between subsequent
invocations of a method on the same instance. invocations of a method on the same instance.
.. versionadded:: 1.8
You can use the ``name`` argument to make cached properties of other
methods. For example, if you had an expensive ``get_friends()`` method and
wanted to allow calling it without retrieving the cached value, you could
write::
friends = cached_property(get_friends, name='friends')
While ``person.get_friends()`` will recompute the friends on each call, the
value of the cached property will persist until you delete it as described
above::
x = person.friends # calls first time
y = person.get_friends() # calls again
z = person.friends # does not call
x is z # is True
.. function:: allow_lazy(func, *resultclasses) .. function:: allow_lazy(func, *resultclasses)
Django offers many utility functions (particularly in ``django.utils``) Django offers many utility functions (particularly in ``django.utils``)

View File

@ -52,6 +52,11 @@ class FunctionalTestCase(unittest.TestCase):
def value(self): def value(self):
return 1, object() return 1, object()
def other_value(self):
return 1
other = cached_property(other_value, name='other')
a = A() a = A()
# check that it is cached # check that it is cached
@ -67,6 +72,10 @@ class FunctionalTestCase(unittest.TestCase):
# check that it behaves like a property when there's no instance # check that it behaves like a property when there's no instance
self.assertIsInstance(A.value, cached_property) self.assertIsInstance(A.value, cached_property)
# check that overriding name works
self.assertEqual(a.other, 1)
self.assertTrue(callable(a.other_value))
def test_lazy_equality(self): def test_lazy_equality(self):
""" """
Tests that == and != work correctly for Promises. Tests that == and != work correctly for Promises.