{"id":840,"library":"cached-property","title":"Cached Property","description":"cached-property (current version 2.0.1) is a Python decorator for caching the results of properties in classes. It provides a straightforward way to memoize expensive computations, executing them only once per instance and storing the result as a regular attribute. The library offers basic, thread-safe, and time-based (TTL) caching mechanisms, as well as experimental async/await compatibility. It maintains an active development status with releases typically aligned with Python version support updates.","status":"active","version":"2.0.1","language":"python","source_language":"en","source_url":"https://github.com/pydanny/cached-property","tags":["caching","decorator","performance","property","memoization"],"install":[{"cmd":"pip install cached-property","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"symbol":"cached_property","correct":"from cached_property import cached_property"},{"symbol":"threaded_cached_property","correct":"from cached_property import threaded_cached_property"},{"symbol":"cached_property_with_ttl","correct":"from cached_property import cached_property_with_ttl"},{"symbol":"threaded_cached_property_with_ttl","correct":"from cached_property import threaded_cached_property_with_ttl"}],"quickstart":{"code":"from cached_property import cached_property\n\nclass Monopoly:\n    def __init__(self):\n        self.boardwalk_price = 500\n\n    @cached_property\n    def boardwalk(self):\n        # In reality, this might represent a database call or time\n        # intensive task like calling a third-party API.\n        self.boardwalk_price += 50\n        return self.boardwalk_price\n\nmonopoly = Monopoly()\nprint(f\"First access: {monopoly.boardwalk}\")\nprint(f\"Second access (cached): {monopoly.boardwalk}\")\n\n# To invalidate the cache, delete the attribute:\ndel monopoly.__dict__['boardwalk'] # Or del monopoly.boardwalk for simple cases\nprint(f\"After invalidation: {monopoly.boardwalk}\")","lang":"python","description":"This example demonstrates how to use the `cached_property` decorator to cache an expensive property computation. The `boardwalk` property will only execute its logic once per instance, returning the cached value on subsequent accesses until explicitly invalidated."},"warnings":[{"fix":"Upgrade your Python environment to 3.8+ or pin `cached-property` to a compatible version (e.g., `cached-property<2.0.0` for Python <3.8).","message":"Version 2.0.0 of `cached-property` officially dropped support for Python versions older than 3.8. Users on Python 2.7 or 3.7 and below should stick to `cached-property` version 1.5.2 or earlier.","severity":"breaking","affected_versions":"<2.0.0"},{"fix":"For basic caching in Python 3.8+, consider using `from functools import cached_property`. If you require TTL or explicit thread-safe caching, `cached-property` remains a viable choice.","message":"Python 3.8+ introduced `functools.cached_property` into the standard library. For basic property caching in Python 3.8+, `functools.cached_property` is generally preferred. `cached-property` provides additional features like time-to-live (TTL) and thread-safe variants that are not present in `functools.cached_property`.","severity":"gotcha","affected_versions":"2.0.0+"},{"fix":"Be aware of this limitation when using TTL features. If immediate invalidation is critical, consider using the base `cached_property` and managing invalidation manually (`del obj.property_name`) or designing around the TTL expiration.","message":"The `cached_property_with_ttl` and `threaded_cached_property_with_ttl` functions do not reliably allow manual invalidation of the cache. This means that once a value is cached with a TTL, it might not be possible to force a re-computation before the TTL expires.","severity":"gotcha","affected_versions":"1.0.0+"},{"fix":"Avoid mixing `asyncio` with threading if possible. If necessary, ensure proper synchronization and careful management of event loops across threads to prevent data corruption or incorrect cached values.","message":"When combining `asyncio` with threading, especially with the `ttl` versions, be aware that most `asyncio` objects are not thread-safe. Running separate event loops in different threads can lead to unexpected behavior with cached values.","severity":"gotcha","affected_versions":"1.0.0+"},{"fix":"Prefer `del obj.property_name` for simple cache invalidation. Ensure your application logic correctly triggers invalidation when the underlying data changes, as the decorator itself does not automatically detect state changes.","message":"Invalidating a `cached_property` is typically done by deleting the attribute (`del obj.property_name`). The library's quickstart sometimes shows `del obj.__dict__['property_name']` which is equivalent but can be less idiomatic. Both methods clear the cached value, allowing the property method to run again on next access.","severity":"gotcha","affected_versions":"1.0.0+"}],"env_vars":null,"search_vec":"'2.0.1':8 'activ':67 'align':73 'async/await':62 'attribut':43 'base':54 'basic':47 'cach':1,4,14,56,79 'cached-properti':3 'class':20 'compat':63 'comput':29 'current':6 'decor':12,80 'develop':68 'execut':30 'expens':28 'experiment':61 'instanc':35 'librari':45 'maintain':65 'mechan':57 'memoiz':27,83 'offer':46 'per':34 'perform':81 'properti':2,5,18,82 'provid':22 'python':11,75 'regular':42 'releas':71 'result':16,39 'safe':50 'status':69 'store':37 'straightforward':24 'support':77 'thread':49 'thread-saf':48 'time':53 'time-bas':52 'ttl':55 'typic':72 'updat':78 'version':7,76 'way':25 'well':59","created_at":"2026-03-29T06:04:14.765636+00:00","updated_at":"2026-04-16T01:14:01.601396+00:00","problems":[{"fix":"To use the `cached-property` library (version 2.0.1 requires Python 3.8+), ensure it's installed (`pip install cached-property`) and import it directly: `from cached_property import cached_property`. If you specifically intend to use the standard library `functools.cached_property`, ensure your Python environment is version 3.8 or newer.","cause":"This error occurs when attempting to import `cached_property` from Python's built-in `functools` module in a Python version prior to 3.8, where it was not yet available, or when confusing the standard library `cached_property` with the external `cached-property` package.","error":"ImportError: cannot import name 'cached_property' from 'functools'"},{"fix":"If you need a writable property with caching, you typically manage cache invalidation manually within a custom setter (e.g., `del self.__dict__['my_property']`) or by defining a standard `@property` with a `@my_property.setter` and implementing explicit caching logic there.","cause":"The `cached_property` decorator (both from the external `cached-property` library and `functools`) is designed for properties whose values are computed once and then cached as effectively immutable attributes; it does not inherently support the `.setter` method like a standard `property` decorator.","error":"AttributeError: 'cached_property' object has no attribute 'setter'"},{"fix":"To use `cached_property` with `__slots__`, you must include `'__dict__'` in your `__slots__` definition (e.g., `__slots__ = ('my_attribute', '__dict__')`) to provide a mutable dictionary for caching. Alternatively, avoid `__slots__` if memory optimization is not critical, or consider using `functools.lru_cache` on a regular method if applicable.","cause":"This error commonly arises when `cached_property` is used with classes that define `__slots__` but do not include `'__dict__'` in their `__slots__` definition. `cached_property` relies on writing the cached value to the instance's `__dict__`, which is unavailable or immutable in such cases.","error":"TypeError: Cannot use cached_property instance without calling __set_name__ on it."},{"fix":"For thread-safe caching with the `cached-property` library, use the `threaded_cached_property` decorator (`from cached_property import threaded_cached_property`). If you were relying on the removed `functools.cached_property` lock, you must implement explicit locking within your getter function or around access points to ensure thread synchronization.","cause":"This error specifically occurs in Python 3.12 and later versions when code attempts to access an undocumented `lock` attribute on a `cached_property` instance. The internal, class-wide locking mechanism of `functools.cached_property` (which caused performance issues) was removed in Python 3.12.","error":"AttributeError: 'cached_property' object has no attribute 'lock'"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":"2.0.1","cli_name":"","cli_version":null,"type":"library","homepage":null,"github":"https://github.com/pydanny/cached-property","docs":null,"changelog":null,"pypi":"https://pypi.org/project/cached-property/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["serialization","database","web-framework"],"base_url":null,"auth_type":null,"provenance":{"verified_status":"passing","verified_at":"2026-06-28","last_verified":"2026-06-28","next_check":"2026-07-28","install_tag":"verified"}}