properties.pyx
1 from cpython.dict cimport ( 2 PyDict_Contains, 3 PyDict_GetItem, 4 PyDict_SetItem, 5 ) 6 from cython cimport Py_ssize_t 7 8 9 cdef class CachedProperty: 10 11 cdef readonly: 12 object fget, name, __doc__ 13 14 def __init__(self, fget): 15 self.fget = fget 16 self.name = fget.__name__ 17 self.__doc__ = getattr(fget, '__doc__', None) 18 19 def __get__(self, obj, typ): 20 if obj is None: 21 # accessed on the class, not the instance 22 return self 23 24 # Get the cache or set a default one if needed 25 cache = getattr(obj, '_cache', None) 26 if cache is None: 27 try: 28 cache = obj._cache = {} 29 except (AttributeError): 30 return self 31 32 if PyDict_Contains(cache, self.name): 33 # not necessary to Py_INCREF 34 val = <object>PyDict_GetItem(cache, self.name) 35 else: 36 val = self.fget(obj) 37 PyDict_SetItem(cache, self.name, val) 38 return val 39 40 def __set__(self, obj, value): 41 raise AttributeError("Can't set attribute") 42 43 44 cache_readonly = CachedProperty 45 46 47 cdef class AxisProperty: 48 49 cdef readonly: 50 Py_ssize_t axis 51 object __doc__ 52 53 def __init__(self, axis=0, doc=""): 54 self.axis = axis 55 self.__doc__ = doc 56 57 def __get__(self, obj, type): 58 cdef: 59 list axes 60 61 if obj is None: 62 # Only instances have _mgr, not classes 63 return self 64 else: 65 axes = obj._mgr.axes 66 return axes[self.axis] 67 68 def __set__(self, obj, value): 69 obj._set_axis(self.axis, value)