{ "info": { "author": "Felipe A. Hernandez", "author_email": "ergoithz@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3" ], "description": "# lfudacache\n\nPython implementation Less Frequently Used with Dynamic Aging (LFUDA),\nimplementing an ordered dict-like interface, providing efficient cache with\nreduced cache pollution.\n\n## Installation\n\n```sh\npip install lfudacache\n```\n\n## Usage\n\n```python\nimport lfudacache\n\ncache = lfudacache.LFUDACache(1000) # cache the top 1000 most frequently accessed items\ncache['key1'] = 1\ncache.get('key1') # 1\nlist(cache.items()) # [('key1', 1)]\ncache['key2'] = 2\nlist(cache.items()) # [('key1', 1), ('key2', 2)]\ncache.get('key2') # 2\nlist(cache.items()) # [('key2', 2), ('key1', 1)]\ncache.peek('key1') # 1\nlist(cache.items()) # [('key2', 2), ('key1', 1)]\ncache.get('key3') # None\nlist(cache.items()) # [('key2', 2), ('key1', 1)]\ncache['key3'] = 3\nlist(cache.items()) # [('key3', 3), ('key2', 2), ('key1', 1)]\n```\n\nA function memoization decorator is also available. Please note that,\nunhashable arguments will raise `TypeError` just like python's standard\n`functools.lru_cache`.\n\n```python\nimport lfudacache\n\n@lfudacache.memoize(1000) # cache the top 1000 most frequent call results\ndef my_cached_function(param_1, param_2):\n result = my_very_expensive_logic(param_1, param_2)\n return result\n```\n\n## Documentation\n\n**LFUDACache** objects implement the `MutableMapping` interface, behaving like any\nother python `dict` (actually, more like an `OrderedDict` as it's ordered).\nbut expiring long **unused** items when new ones are inserted.\n\nAn item is considered **unused** when cache **ages** above item **hits**.\n\nCache **ages** when asked for a missing **key** .\n\nInserting an item when cache is not enough **aged** will result on the item\nnot being stored, reducing cache pollution.\n\n**LFUDACache** iteration will start from most to less frequently used items.\n\n### `LFUDACache`\n\n```\nLess Frequently Used with Dynamic Aging cache, implementing the entire\n:class:`collections.abc.MutableMapping' interface.\n\nImplementation notes:\n * Most methods are self-optimizing into closures when referenced.\n * Cache behaves as as dict, all operations (except iteration or peek)\n count as cache MISS or HIT, affecting key ordering or insertion\n permeability.\n\nHow it works:\n * Every cache hit increases item HIT counter\n (except :method:`LFUDACache.peek`).\n * Every cache miss increases MISSES counter by 1, up to top HITS.\n * When full, a new cache item will only be accepted if MISSES counter\n reaches the less frequently used item HIT counter, which is evicted.\n * When a new item is cached, its HIT counter is set equal to MISSES\n itself.\n * When an existing item is updated, its HIT counter is incremented\n by 1 to at least MISSES + 1.\n```\n\n#### `LFUDACache.__init__(maxsize)`\n\n```\n:param maxsize: number of items to keep on cache\n:type maxsize: int\n```\n\n#### `LFUDACache.peek(key [, default])`\n\n```\nGet value of key from cache, without updating HIT nor MISSES counters.\n\nIf key is not found, and default is not given, KeyError is raised.\n\n:param key: cache item key\n:param default: optional default parameter\n:returns: cache item value\n:raises KeyError: if no default is given and key is not found\n\nUsage\n-----\nvalue = lfudacache.peek(key, 'default_value')\n```\n\n### `memoize(maxsize, fnc=None, key_fnc=make_key)`\n\n```\nMemoization decorator using Less Frequenty Used with Dynamic Aging cache\neviction algorithm.\n\nThe LFUDACache instance is available on the decorated function, as `cache`\nproperty.\n\n:param maxsize: maximum cache size\n:type maxsize: int\n:param fnc: optional function to memoize (non-decorating behavior)\n:type fnc: callable or None\n:param key_fnc: optional custom cache key function, receiving argument\n list and keyword argument dict\n:type key_fnc: callable\n:returns: decorator if fnc is not given, wrapped function otherwise\n:rtype: callable\n```\n\n### `make_key(args, kwargs)`\n\n```\nHash function for function arguments.\n\n:param args: argument iterable\n:type args: iterable\n:param kwargs: keyword argument dict-like object\n:type kwargs: dict\n:returns: hash of arg and kwargs\n:rtype: int\n```\n\n## Rationale\n\nThere is a lot of LFU and LRU cache implementations for Python, but not so\nmany LFUDA ones, and some of them were a bit too slow due to python attribute\nlookup overhead (thats why python's standard lru_cache implementation is\npurely functional).\n\nThis module addresses this performance concerns by making extensive use\nof python closures, while providing an object-oriented interface, via a\nself-optimizing implementation.\n\n### Why Less Frequently Used with Dynamic Aging (LFUDA)\n\nLFUDA only evicts less used items when they become too old, rejecting new cache\nitems until then.\n\nIn our implementation, an item become too old when its cache hit count lags\nbehind the entire cache misses.\n\nThis approach prevents eviction of very used items in favor of potentially less\nused items.\n\n### Why not Less Recently Used (LRU)\n\nLRU is a very simple approach to caching, evicting older unused items.\n\nThis approach is optimal when the most relevant items are accessed frequently,\nbut this is not always the case.\n\nThe drawback is that very used items will be evicted when a lot of new items\nare added to cache, even if they will never be accesed again, causing cache\npollution.\n\nThis problem is usually minimized increasing the cache size until potentially\nirrelevant cache items become only a tiny fraction of the entire cache but\nthis is not always possible or memory efficient.\n\n### Why not Less Frequenty Used (LFU)\n\nLFU is our base algorithm, which evicts less used items.\n\nThis approach has one major drawback when cache is full: a new saved item\ncould cause the eviction of an item more frequently used than the new one,\ncausing cache pollution.\n\nTo minimize this problem, two different item storage tiers can be implemented\nwith different eviction policies. But while this method reduces said cache\npollution issue, it does not fix it.\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://gitlab.com/ergoithz/lfudacache", "keywords": "cache,memoize", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "lfudacache", "package_url": "https://pypi.org/project/lfudacache/", "platform": "any", "project_url": "https://pypi.org/project/lfudacache/", "project_urls": { "Homepage": "https://gitlab.com/ergoithz/lfudacache" }, "release_url": "https://pypi.org/project/lfudacache/0.0.2/", "requires_dist": null, "requires_python": "", "summary": "Less Frequently Used with Dynamic Aging", "version": "0.0.2" }, "last_serial": 5403757, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "4f24c3774eadc441c2e12b98fbd87701", "sha256": "b31661e2fb10eb8a678d2dbe4c6bf267f513b46e694ce2f5eb2df2dd30adf90d" }, "downloads": -1, "filename": "lfudacache-0.0.1-py2-none-any.whl", "has_sig": false, "md5_digest": "4f24c3774eadc441c2e12b98fbd87701", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 11771, "upload_time": "2017-10-29T17:20:30", "url": "https://files.pythonhosted.org/packages/41/25/6d5f0bc58c681901397864a818925e61541243d14959fd9f90c5cd3288b2/lfudacache-0.0.1-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2718d447f7d0c734c9e5c7b91fefaf63", "sha256": "2ca733901ef9d491f963c124dc58f519f9be611dfd5f68240e3610280b719734" }, "downloads": -1, "filename": "lfudacache-0.0.1.tar.gz", "has_sig": false, "md5_digest": "2718d447f7d0c734c9e5c7b91fefaf63", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7492, "upload_time": "2017-10-29T17:20:31", "url": "https://files.pythonhosted.org/packages/ae/2f/3bf7fa50a9eb81890dfe17c5a8514faa304d843ed4e3c710ad9921790871/lfudacache-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "cf77d94d28c615a71402596bfb27be93", "sha256": "770a3a457b1f19efa6ea67be2fd80cfa6e2b8a22345bcf86ef74e546d92c1576" }, "downloads": -1, "filename": "lfudacache-0.0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "cf77d94d28c615a71402596bfb27be93", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 11019, "upload_time": "2019-06-15T10:58:44", "url": "https://files.pythonhosted.org/packages/fd/68/4684c19e33e7797306bcd993c377b0d620ad62db3f504e561d415ef12d67/lfudacache-0.0.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "19ba27e10363c50b1e4c3c51b21a22a0", "sha256": "785cde4fa7a314a83683f8fd61ebc894d55ff4a87b4d148c76544f860cea1cc9" }, "downloads": -1, "filename": "lfudacache-0.0.2.tar.gz", "has_sig": false, "md5_digest": "19ba27e10363c50b1e4c3c51b21a22a0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10747, "upload_time": "2019-06-15T10:58:46", "url": "https://files.pythonhosted.org/packages/b6/bb/31fae39f7725d6c75d66f3a7fe71e00b0cd18c4fc9e3fa5a8f8f0b3a2ec5/lfudacache-0.0.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "cf77d94d28c615a71402596bfb27be93", "sha256": "770a3a457b1f19efa6ea67be2fd80cfa6e2b8a22345bcf86ef74e546d92c1576" }, "downloads": -1, "filename": "lfudacache-0.0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "cf77d94d28c615a71402596bfb27be93", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 11019, "upload_time": "2019-06-15T10:58:44", "url": "https://files.pythonhosted.org/packages/fd/68/4684c19e33e7797306bcd993c377b0d620ad62db3f504e561d415ef12d67/lfudacache-0.0.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "19ba27e10363c50b1e4c3c51b21a22a0", "sha256": "785cde4fa7a314a83683f8fd61ebc894d55ff4a87b4d148c76544f860cea1cc9" }, "downloads": -1, "filename": "lfudacache-0.0.2.tar.gz", "has_sig": false, "md5_digest": "19ba27e10363c50b1e4c3c51b21a22a0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10747, "upload_time": "2019-06-15T10:58:46", "url": "https://files.pythonhosted.org/packages/b6/bb/31fae39f7725d6c75d66f3a7fe71e00b0cd18c4fc9e3fa5a8f8f0b3a2ec5/lfudacache-0.0.2.tar.gz" } ] }