Rewrite the snippet I wrote earlier. Once read, the property will be retained until the object is destroyed. That's the specification.
You can also write to use a proper cache by specifying a cache backend for the decorator variable. Let's do it later
dec.py
from functools import wraps
import mox
from unittest import TestCase
def cached_property(f):
prefix = '_cached_property_'
@wraps(f)
def _cached_property(self):
key = prefix + f.__name__
if hasattr(self, key):
return getattr(self, key)
value = f(self)
setattr(self, key, value)
return value
return property(_cached_property)
class TestCachedProperty(TestCase):
def setUp(self):
self.m = mox.Mox()
def tearDown(self):
self.m.UnsetStubs()
self.m = None
def test_call_1(self):
"""Simple call."""
# Procuder function that should be called twice.
producer = self.m.CreateMockAnything()
producer().AndReturn(30)
producer().AndReturn(101)
producer().AndReturn(None)
producer().AndReturn(0)
producer().AndReturn('')
class C(object):
@cached_property
def f(self):
return producer()
# Try
self.m.ReplayAll()
c = C()
c2 = C()
c3 = C()
c4 = C()
c5 = C()
# Verify
self.assertEqual(c.f, 30)
self.assertEqual(c.f, 30)
self.assertEqual(c._cached_property_f, 30)
self.assertEqual(c2.f, 101)
self.assertEqual(c2.f, 101)
self.assertEqual(c2._cached_property_f, 101)
self.assertEqual(c3.f, None)
self.assertEqual(c3.f, None)
self.assertEqual(c3._cached_property_f, None)
self.assertEqual(c4.f, 0)
self.assertEqual(c4.f, 0)
self.assertEqual(c4._cached_property_f, 0)
self.assertEqual(c5.f, '')
self.assertEqual(c5.f, '')
self.assertEqual(c5._cached_property_f, '')
self.m.VerifyAll()
return
def test_call_2(self):
"""Check that property function reference self."""
# Procuder function that should be called once.
producer = self.m.CreateMockAnything()
producer().AndReturn(30)
producer().AndReturn(101)
class C(object):
@cached_property
def f(self):
return self.g()
def g(self):
return producer()
# Try
self.m.ReplayAll()
c = C()
c2 = C()
# Verify
self.assertEqual(c.f, 30)
self.assertEqual(c.f, 30)
self.assertEqual(c._cached_property_f, 30)
self.assertEqual(c2.f, 101)
self.assertEqual(c2.f, 101)
self.assertEqual(c2._cached_property_f, 101)
self.m.VerifyAll()
return