diff --git a/CHANGES/1122.misc.rst b/CHANGES/1122.misc.rst new file mode 100644 index 000000000..a911c35e9 --- /dev/null +++ b/CHANGES/1122.misc.rst @@ -0,0 +1 @@ +Improved performance of the Cython ``cached_property`` implementation -- by :user:`bdraco`. diff --git a/yarl/_helpers_c.pyx b/yarl/_helpers_c.pyx index c428753d2..e6eec3754 100644 --- a/yarl/_helpers_c.pyx +++ b/yarl/_helpers_c.pyx @@ -1,5 +1,7 @@ # cython: language_level=3 +cdef _sentinel = object() + cdef class cached_property: """Use as a class method decorator. It operates almost exactly like the Python `@property` decorator, but it puts the result of the @@ -21,17 +23,14 @@ cdef class cached_property: return self.wrapped.__doc__ def __get__(self, inst, owner): - try: - try: - return inst._cache[self.name] - except KeyError: - val = self.wrapped(inst) - inst._cache[self.name] = val - return val - except AttributeError: - if inst is None: - return self - raise + if inst is None: + return self + cdef dict cache = inst._cache + val = cache.get(self.name, _sentinel) + if val is _sentinel: + val = self.wrapped(inst) + cache[self.name] = val + return val def __set__(self, inst, value): raise AttributeError("cached property is read-only")