EDIT : If all of your keys are strings, then before you continue reading this answer, please check out Jack O'Connor, a much simpler (and faster) solution (which also works for hashing nested dictionaries).
Although the answer is accepted, the title of the question is "Hashing the Python Dictionary", and the answer is incomplete for this title. (As for the main part of the question, the answer is complete.)
Nested Dictionaries
If someone is looking in Kara for a way to hash a dictionary, he may stumble upon this aptly titled question and leave him unsatisfied if someone tries to hash several nested dictionaries. The answer above will not work in this case, and you will have to implement some kind of recursive mechanism to extract the hash.
Here is one such mechanism:
import copy def make_hash(o): """ Makes a hash from a dictionary, list, tuple or set to any level, that contains only other hashable types (including any lists, tuples, sets, and dictionaries). """ if isinstance(o, (set, tuple, list)): return tuple([make_hash(e) for e in o]) elif not isinstance(o, dict): return hash(o) new_o = copy.deepcopy(o) for k, v in new_o.items(): new_o[k] = make_hash(v) return hash(tuple(frozenset(sorted(new_o.items()))))
Bonus: hashing objects and classes
The hash() function works great when you hash() classes or instances. However, here is one problem I discovered with a hash regarding objects:
class Foo(object): pass foo = Foo() print (hash(foo))
The hash remains the same even after I changed foo. This is because the identity of foo has not changed, so the hash remains the same. If you want foo to hash differently depending on its current definition, the solution is to hash everything that actually changes. In this case, the __dict__ attribute:
class Foo(object): pass foo = Foo() print (make_hash(foo.__dict__))
Alas, when you try to do the same with the class itself:
print (make_hash(Foo.__dict__))
The class __dict__ property is not a regular dictionary:
print (type(Foo.__dict__))
Here is a mechanism similar to the previous one that will handle classes accordingly:
import copy DictProxyType = type(object.__dict__) def make_hash(o): """ Makes a hash from a dictionary, list, tuple or set to any level, that contains only other hashable types (including any lists, tuples, sets, and dictionaries). In the case where other kinds of objects (like classes) need to be hashed, pass in a collection of object attributes that are pertinent. For example, a class can be hashed in this fashion: make_hash([cls.__dict__, cls.__name__]) A function can be hashed like so: make_hash([fn.__dict__, fn.__code__]) """ if type(o) == DictProxyType: o2 = {} for k, v in o.items(): if not k.startswith("__"): o2[k] = v o = o2 if isinstance(o, (set, tuple, list)): return tuple([make_hash(e) for e in o]) elif not isinstance(o, dict): return hash(o) new_o = copy.deepcopy(o) for k, v in new_o.items(): new_o[k] = make_hash(v) return hash(tuple(frozenset(sorted(new_o.items()))))
You can use this to return a hash tuple from any number of elements that you need:
# -7666086133114527897 print (make_hash(func.__code__)) # (-7666086133114527897, 3527539) print (make_hash([func.__code__, func.__dict__])) # (-7666086133114527897, 3527539, -509551383349783210) print (make_hash([func.__code__, func.__dict__, func.__name__]))
NOTE: all of the above code assumes the use of Python 3.x. Not tested in earlier versions, although I assume that make_hash() will work, say, in 2.7.2. As for the examples, I know that
func.__code__
should be replaced by
func.func_code