from collections.abc import Iterator from itertools import tee from typing import Tuple, List, Collection, Dict, Set, Type def safehash(obj)->int: ''' Tool to take a hash of an object in a safe way. The idea is that it intercepts non-hashable types and works around it. ''' try: # first try the dumb way, because the safe way is expensive # see also #357 return obj.__hash__() except TypeError: # the constants are to distinguish between the types if isinstance(obj, Set): #order irrelevant return 17+sum([safehash(it) for it in obj]) if isinstance(obj, Dict): # order irrelevant. return 133+sum([safehash(item) for item in obj.items() ]) if isinstance(obj, List) or isinstance(obj, tuple): # order is important return 31+hash( tuple ( safehash(elt) for elt in obj ) ) if isinstance(obj, type): return hash(obj) raise ValueError("Type not yet handled: "+str(obj))