Complete the cachedproperty descriptor protocol

Refactor some parts of the cachedproperty property
descriptor (renaming attributes to the standard names
used in descriptor objects) and add on the __set__ and
__delete__ methods to comply with the full descriptor
protocol.

Change-Id: I1f1e8e301271c060d14acc3a77c094dabd120f16
This commit is contained in:
Joshua Harlow
2014-05-20 00:05:10 -07:00
parent 1ebebd453d
commit b9afecb86e

View File

@@ -180,30 +180,37 @@ class cachedproperty(object):
those methods into properties that will be cached in the instance (avoiding those methods into properties that will be cached in the instance (avoiding
repeated creation checking logic to do the equivalent). repeated creation checking logic to do the equivalent).
""" """
def __init__(self, wrapped): def __init__(self, fget):
# If a name is provided (as an argument) then this will be the string # If a name is provided (as an argument) then this will be the string
# to place the cached attribute under if not then it will be the # to place the cached attribute under if not then it will be the
# function itself to be wrapped into a property. # function itself to be wrapped into a property.
if inspect.isfunction(wrapped): if inspect.isfunction(fget):
self._wrapped = wrapped self._fget = fget
self._wrapped_attr = "_%s" % (wrapped.__name__) self._attr_name = "_%s" % (fget.__name__)
else: else:
self._wrapped_attr = wrapped self._attr_name = fget
self._wrapped = None self._fget = None
def __call__(self, fget): def __call__(self, fget):
# If __init__ received a string then this will be the function to be # If __init__ received a string then this will be the function to be
# wrapped as a property (if __init__ got a function then this will not # wrapped as a property (if __init__ got a function then this will not
# be called). # be called).
self._wrapped = fget self._fget = fget
return self return self
def __get__(self, source, owner): def __set__(self, instance, value):
raise AttributeError("can't set attribute")
def __delete__(self, instance):
raise AttributeError("can't delete attribute")
def __get__(self, instance, owner):
try: try:
return getattr(source, self._wrapped_attr) return getattr(instance, self._attr_name)
except AttributeError: except AttributeError:
setattr(source, self._wrapped_attr, self._wrapped(source)) value = self._fget(instance)
return getattr(source, self._wrapped_attr) setattr(instance, self._attr_name, value)
return value
def wallclock(): def wallclock():