Tests of the ``cached_property`` function, which computes
the property value on first access and stores it in the
instance dict, so subsequent accesses are just simple
attribute references.

    >>> from plib.stdlib.decotools import cached_property
    >>> class Test(object):
    ...     def test(self):
    ...         print("Doing initial calculation...")
    ...         return "Test done."
    ...     test = cached_property(test)
    ... 
    >>> t = Test()
    >>> 'test' in t.__dict__
    False
    >>> print(t.test)
    Doing initial calculation...
    Test done.
    >>> 'test' in t.__dict__
    True
    >>> print(t.test)
    Test done.

The cached value can be explicitly deleted from the instance
dict, or overwritten by an explicit assignment to the
attribute. Deletion "resets" the property, so it has to be
computed again on the next access.

    >>> del t.test
    >>> 'test' in t.__dict__
    False
    >>> t.test = "Other value."
    >>> print(t.test)
    Other value.
    >>> del t.test
    >>> print(t.test)
    Doing initial calculation...
    Test done.

One other wrinkle: ``hasattr`` also triggers the property
computation.

    >>> del t.test
    >>> hasattr(t, 'test')
    Doing initial calculation...
    True
    >>> 'test' in t.__dict__
    True
    >>> print(t.test)
    Test done.
