methodtools.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. """:mod:`methodtools` --- functools for methods
  2. ===============================================
  3. Expand functools features to methods, classmethods, staticmethods and even for
  4. (unofficial) hybrid methods.
  5. For now, methodtools only provides :func:`methodtools.lru_cache`.
  6. Use methodtools module instead of functools module. Than it will work as you
  7. expected - cache for each bound method.
  8. .. code-block:: python
  9. from methodtools import lru_cache
  10. class A(object):
  11. # cached method. the storage lifetime follows `self` object
  12. @lru_cache()
  13. def cached_method(self, args):
  14. ...
  15. # cached classmethod. the storage lifetime follows `A` class
  16. @lru_cache() # the order is important!
  17. @classmethod # always lru_cache on top of classmethod
  18. def cached_classmethod(self, args):
  19. ...
  20. # cached staticmethod. the storage lifetime follows `A` class
  21. @lru_cache() # the order is important!
  22. @staticmethod # always lru_cache on top of staticmethod
  23. def cached_staticmethod(self, args):
  24. ...
  25. @lru_cache() # just same as functools.lru_cache
  26. def cached_function():
  27. ...
  28. """
  29. import functools
  30. from wirerope import Wire, WireRope
  31. __version__ = '0.4.7'
  32. __all__ = 'lru_cache',
  33. if hasattr(functools, 'lru_cache'):
  34. _functools_lru_cache = functools.lru_cache
  35. else:
  36. try:
  37. import functools32
  38. except ImportError:
  39. # raise AttributeError about fallback failure
  40. functools.lru_cache # install `functools32` to run on py2
  41. else:
  42. _functools_lru_cache = functools32.lru_cache
  43. class _LruCacheWire(Wire):
  44. def __init__(self, rope, *args, **kwargs):
  45. super(_LruCacheWire, self).__init__(rope, *args, **kwargs)
  46. lru_args, lru_kwargs = rope._args
  47. wrapper = _functools_lru_cache(
  48. *lru_args, **lru_kwargs)(self.__func__)
  49. self.__call__ = wrapper
  50. self.cache_clear = wrapper.cache_clear
  51. self.cache_info = wrapper.cache_info
  52. def __call__(self, *args, **kwargs):
  53. # descriptor detection support - never called
  54. return self.__call__(*args, **kwargs)
  55. def _on_property(self):
  56. return self.__call__()
  57. @functools.wraps(_functools_lru_cache)
  58. def lru_cache(*args, **kwargs):
  59. return WireRope(_LruCacheWire, wraps=True, rope_args=(args, kwargs))