cached_method


Namecached_method JSON
Version 0.1.0 PyPI version JSON
download
home_page
SummaryThe equivalent of cached_property for methods
upload_time2021-10-31 19:38:21
maintainer
docs_urlNone
author
requires_python>= 3.6
license
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # cached_method

The `@cached_method` decorator is the equivalent of
[`functools.cached_property`](https://docs.python.org/3/library/functools.html#functools.cached_property)
for methods. This means that each instance has its own cache, so that the caches get
garbage collected as soon as the owning objects are. The main advantages of
`cached_method` over applying `functools.lru_cache` directly to methods are
1. the surrounding class need not be hashable,
2. and the class objects are not collected in a global cache, extending their lifetime.
This makes `cached_method` applicable to classes holding references to scarce resources
such as GPU memory that you want to be freed as soon as possible. Furthermore, the
decorator can cache the output of `__hash__` because it does not hash the object itself
for cache lookups.

Implementation-wise `cached_method` closely follows `functools.cached_property` though it
eschews the internal locking, which is now [considered a
mistake](https://bugs.python.org/issue43468). Since cached methods should be idempotent
anyway, we just accept possibly calling the method multiple times in parallel with
equivalent arguments if the object is used in multi-threaded contexts.

```python
from cached_method import cached_method

class GPUVector:
    def __init__(self, data):
        # data is some smart tensor object as found in pytorch, tensorflow, etc.
        self.data = data

    # Only cache the 2 most-recently used norms
    @cached_method(maxsize=2)
    def norm(self, p=2):
        return (self.data ** p).sum() ** (1 / p)

    @cached_method
    def __hash__(self):
        # A costly GPU-to-CPU transfer, so we want to hash the result
        return hash(tuple(self.data.to_cpu()))
```

If you are working with small, hashable objects that do not have to be gargabe collected
as soon as possible, consider the [method hashing technique described in the Python
FAQ](https://docs.python.org/3/faq/programming.html#how-do-i-cache-method-calls). It gives
you an easy way to control the total cache size and allows cache hits between
equivalent-but-not-identical objects. Of course, caching on the class level means that
objects stay live until you clear the cache manually, even if the cache is the last object
referencing them.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "cached_method",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">= 3.6",
    "maintainer_email": "",
    "keywords": "",
    "author": "",
    "author_email": "Marten Lienen <marten.lienen@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/85/57/f5796619b29cfbbce98b6027f9f92461a9c159a373566106a11b2bab1e07/cached_method-0.1.0.tar.gz",
    "platform": "",
    "description": "# cached_method\n\nThe `@cached_method` decorator is the equivalent of\n[`functools.cached_property`](https://docs.python.org/3/library/functools.html#functools.cached_property)\nfor methods. This means that each instance has its own cache, so that the caches get\ngarbage collected as soon as the owning objects are. The main advantages of\n`cached_method` over applying `functools.lru_cache` directly to methods are\n1. the surrounding class need not be hashable,\n2. and the class objects are not collected in a global cache, extending their lifetime.\nThis makes `cached_method` applicable to classes holding references to scarce resources\nsuch as GPU memory that you want to be freed as soon as possible. Furthermore, the\ndecorator can cache the output of `__hash__` because it does not hash the object itself\nfor cache lookups.\n\nImplementation-wise `cached_method` closely follows `functools.cached_property` though it\neschews the internal locking, which is now [considered a\nmistake](https://bugs.python.org/issue43468). Since cached methods should be idempotent\nanyway, we just accept possibly calling the method multiple times in parallel with\nequivalent arguments if the object is used in multi-threaded contexts.\n\n```python\nfrom cached_method import cached_method\n\nclass GPUVector:\n    def __init__(self, data):\n        # data is some smart tensor object as found in pytorch, tensorflow, etc.\n        self.data = data\n\n    # Only cache the 2 most-recently used norms\n    @cached_method(maxsize=2)\n    def norm(self, p=2):\n        return (self.data ** p).sum() ** (1 / p)\n\n    @cached_method\n    def __hash__(self):\n        # A costly GPU-to-CPU transfer, so we want to hash the result\n        return hash(tuple(self.data.to_cpu()))\n```\n\nIf you are working with small, hashable objects that do not have to be gargabe collected\nas soon as possible, consider the [method hashing technique described in the Python\nFAQ](https://docs.python.org/3/faq/programming.html#how-do-i-cache-method-calls). It gives\nyou an easy way to control the total cache size and allows cache hits between\nequivalent-but-not-identical objects. Of course, caching on the class level means that\nobjects stay live until you clear the cache manually, even if the cache is the last object\nreferencing them.\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "The equivalent of cached_property for methods",
    "version": "0.1.0",
    "project_urls": {
        "homepage": "https://github.com/martenlienen/cached_method"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a369f4be248608758ebad3d5954bf468fc98a822c939afbb04f1eaaecfc6be1c",
                "md5": "144e648914174b2612aca8e55135f5a0",
                "sha256": "a71720f7cab565131bb5e4189b6ca5902635435e0e017d0fd1261712d8c3dc0c"
            },
            "downloads": -1,
            "filename": "cached_method-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "144e648914174b2612aca8e55135f5a0",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">= 3.6",
            "size": 4172,
            "upload_time": "2021-10-31T19:38:17",
            "upload_time_iso_8601": "2021-10-31T19:38:17.726696Z",
            "url": "https://files.pythonhosted.org/packages/a3/69/f4be248608758ebad3d5954bf468fc98a822c939afbb04f1eaaecfc6be1c/cached_method-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8557f5796619b29cfbbce98b6027f9f92461a9c159a373566106a11b2bab1e07",
                "md5": "c6ea38eebb04702e274af42c2908f012",
                "sha256": "0958d0422a90e24c215fb61f9633fd9faf566c8f7d15478493989abef8699d73"
            },
            "downloads": -1,
            "filename": "cached_method-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "c6ea38eebb04702e274af42c2908f012",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">= 3.6",
            "size": 4032,
            "upload_time": "2021-10-31T19:38:21",
            "upload_time_iso_8601": "2021-10-31T19:38:21.240888Z",
            "url": "https://files.pythonhosted.org/packages/85/57/f5796619b29cfbbce98b6027f9f92461a9c159a373566106a11b2bab1e07/cached_method-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2021-10-31 19:38:21",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "martenlienen",
    "github_project": "cached_method",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "cached_method"
}
        
Elapsed time: 0.21667s