from cpython.dict cimport ( PyDict_Contains, PyDict_GetItem, PyDict_SetItem, ) from cython cimport Py_ssize_t cdef class CachedProperty: cdef readonly: object fget, name, __doc__ def __init__(self, fget): self.fget = fget self.name = fget.__name__ self.__doc__ = getattr(fget, '__doc__', None) def __get__(self, obj, typ): if obj is None: # accessed on the class, not the instance return self # Get the cache or set a default one if needed cache = getattr(obj, '_cache', None) if cache is None: try: cache = obj._cache = {} except (AttributeError): return self if PyDict_Contains(cache, self.name): # not necessary to Py_INCREF val = PyDict_GetItem(cache, self.name) else: val = self.fget(obj) PyDict_SetItem(cache, self.name, val) return val def __set__(self, obj, value): raise AttributeError("Can't set attribute") cache_readonly = CachedProperty cdef class AxisProperty: cdef readonly: Py_ssize_t axis object __doc__ def __init__(self, axis=0, doc=""): self.axis = axis self.__doc__ = doc def __get__(self, obj, type): cdef: list axes if obj is None: # Only instances have _mgr, not classes return self else: axes = obj._mgr.axes return axes[self.axis] def __set__(self, obj, value): obj._set_axis(self.axis, value)