1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Revised] 値をキャッシュするpropertyデコレータ

Last updated at Posted at 2012-03-16

以前に書いたスニペットの書き直し. 一度読みだしたプロパティはオブジェクトが破棄されるまで保持し続けます. そういう仕様です.

デコレータ変数にキャッシュバックエンドを指定して, ちゃんとしたキャッシュを使う様にも書けるね
あとでやってみよう

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
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?