From 71461b14ab0c5a3801d85738fde3aedd407d7115 Mon Sep 17 00:00:00 2001 From: Curtis Date: Sat, 24 May 2014 20:29:31 +1000 Subject: [PATCH] Fixed #22691 -- Added aliasing to cached_property. --- django/utils/functional.py | 8 ++++++-- docs/ref/utils.txt | 20 +++++++++++++++++++- tests/utils_tests/test_functional.py | 9 +++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/django/utils/functional.py b/django/utils/functional.py index 361b0f14fb..c512084c6e 100644 --- a/django/utils/functional.py +++ b/django/utils/functional.py @@ -45,14 +45,18 @@ class cached_property(object): """ 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): + def __init__(self, func, name=None): self.func = func + self.name = name or func.__name__ def __get__(self, instance, type=None): if instance is None: return self - res = instance.__dict__[self.func.__name__] = self.func(instance) + res = instance.__dict__[self.name] = self.func(instance) return res diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt index 883c388a78..826dd9c7f8 100644 --- a/docs/ref/utils.txt +++ b/docs/ref/utils.txt @@ -423,7 +423,7 @@ Atom1Feed .. module:: django.utils.functional :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 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 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) Django offers many utility functions (particularly in ``django.utils``) diff --git a/tests/utils_tests/test_functional.py b/tests/utils_tests/test_functional.py index b6145ff0d0..e9010b3135 100644 --- a/tests/utils_tests/test_functional.py +++ b/tests/utils_tests/test_functional.py @@ -52,6 +52,11 @@ class FunctionalTestCase(unittest.TestCase): def value(self): return 1, object() + def other_value(self): + return 1 + + other = cached_property(other_value, name='other') + a = A() # 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 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): """ Tests that == and != work correctly for Promises.