You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

52 lines
1.4 KiB

  1. """Key functions for memoizing decorators."""
  2. __all__ = ('hashkey', 'typedkey')
  3. class _HashedTuple(tuple):
  4. """A tuple that ensures that hash() will be called no more than once
  5. per element, since cache decorators will hash the key multiple
  6. times on a cache miss. See also _HashedSeq in the standard
  7. library functools implementation.
  8. """
  9. __hashvalue = None
  10. def __hash__(self, hash=tuple.__hash__):
  11. hashvalue = self.__hashvalue
  12. if hashvalue is None:
  13. self.__hashvalue = hashvalue = hash(self)
  14. return hashvalue
  15. def __add__(self, other, add=tuple.__add__):
  16. return _HashedTuple(add(self, other))
  17. def __radd__(self, other, add=tuple.__add__):
  18. return _HashedTuple(add(other, self))
  19. def __getstate__(self):
  20. return {}
  21. # used for separating keyword arguments; we do not use an object
  22. # instance here so identity is preserved when pickling/unpickling
  23. _kwmark = (_HashedTuple,)
  24. def hashkey(*args, **kwargs):
  25. """Return a cache key for the specified hashable arguments."""
  26. if kwargs:
  27. return _HashedTuple(args + sum(sorted(kwargs.items()), _kwmark))
  28. else:
  29. return _HashedTuple(args)
  30. def typedkey(*args, **kwargs):
  31. """Return a typed cache key for the specified hashable arguments."""
  32. key = hashkey(*args, **kwargs)
  33. key += tuple(type(v) for v in args)
  34. key += tuple(type(v) for _, v in sorted(kwargs.items()))
  35. return key