Using non-hashable Python objects as keys in dictionaries

后端 未结 8 1559
栀梦
栀梦 2020-12-19 16:00

Python doesn\'t allow non-hashable objects to be used as keys in other dictionaries. As pointed out by Andrey Vlasovskikh, there is a nice workaround for the special case of

8条回答
  •  庸人自扰
    2020-12-19 16:06

    I encountered this issue when using a decorator that caches the results of previous calls based on call signature. I do not agree with the comments/answers here to the effect of "you should not do this", but I think it is important to recognize the potential for surprising and unexpected behavior when going down this path. My thought is that since instances are both mutable and hashable, and it does not seem practical to change that, there is nothing inherently wrong with creating hashable equivalents of non-hashable types or objects. But of course that is only my opinion.

    For anyone who requires Python 2.5 compatibility, the below may be useful. I based it on the earlier answer.

    from itertools import imap
    tuplemap = lambda f, data: tuple(imap(f, data))
    def make_hashable(obj):
      u"Returns a deep, non-destructive conversion of given object to an equivalent hashable object"
      if isinstance(obj, list):
        return tuplemap(make_hashable, iter(obj))
      elif isinstance(obj, dict):
        return frozenset(tuplemap(make_hashable, obj.iteritems()))
      elif hasattr(obj, '__hash__') and callable(obj.__hash__):
        try:
          obj.__hash__()
        except:
          if hasattr(obj, '__iter__') and callable(obj.__iter__):
            return tuplemap(make_hashable, iter(obj))
          else:
            raise NotImplementedError, 'object of type %s cannot be made hashable' % (type(obj),)
        else:
          return obj
      elif hasattr(obj, '__iter__') and callable(obj.__iter__):
        return tuplemap(make_hashable, iter(obj))
      else:
        raise NotImplementedError, 'object of type %s cannot be made hashable' % (type, obj)
    

提交回复
热议问题