Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A workaround for Python's missing frozen-dict type? [duplicate]

Tags:

In Python, when you want to use lists as keys of some dictionary, you can turn them into tuples, which are immutable and hence are hashable.

>>> a = {} >>> a[tuple(list_1)] = some_value >>> a[tuple(list_2)] = some_other_value 

The same happens when you want to use set objects as keys of some dictionary - you can build a frozenset, that is again immutable and hence is hashable.

>>> a = {} >>> a[frozenset(set_1)] = some_value >>> a[frozenset(set_2)] = some_other_value 

But it seems that for dictionary there is no equivalent.

A first idea I thought about (and found it bad finally), is to use str(some_dict) as a key. But, dictionaries always use different hash functions (which affects the order of elements), so strings of equal dictionaries may be different.

Is there any workaround known as a good practice, or does anyone have other ideas how to use dictionary-like objects as keys of other dictionaries?

like image 545
SomethingSomething Avatar asked Sep 11 '16 20:09

SomethingSomething


2 Answers

EDIT:

Starting from Python 3.6, dictionaries preserve the insertion order. Therefore, the workaround would vary depending on the used Python version.

For Python < 3.6 (Dictionaries do not preserve insertion order) - use frozenset, so that two sets are equal even if order is different:

>>> a = {'key1' : 'val1', 'key2' : 'val2'} >>> b = frozenset(a.items()) >>> frozenset_restored_to_dict = dict(b) >>> frozenset_restored_to_dict {'key2': 'val2', 'key1': 'val1'} 

Otherwise (Dictionaries preserve insertion order), use tuple. This way, the dictionary can be restored while preserving the order of items, yet, tuples with same items ordered differently will not be equal. A workaround for it would be passing the tuples to a frozenset constructor each time before a comparison is made.

>>> a = {'key1' : 'val1', 'key2' : 'val2'} >>> b = tuple(a.items()) >>> tuple_restored_to_dict = dict(b) >>> tuple_restored_to_dict {'key1': 'val1', 'key2': 'val2'} 

As can be seen in the code, b is a tuple, or a frozenset. Either are immutable and hashable, and can be totally restored to be a regular dictionary like a.

like image 158
SomethingSomething Avatar answered Oct 06 '22 00:10

SomethingSomething


You can try ordered dict or look on these answers:

  • What would a "frozen dict" be?
  • Immutable dictionary, only use as a key for another dictionary
  • How to create an immutable dictionary in python?

and there is even a package on PyPI: https://pypi.python.org/pypi/frozendict

You can also simply convert dict to tuples(sorted(your_dict.items())) and then use as a hash.

UPD: as mentioned in comments, OrderedDict is unhashable. My bad, it is really should not be hashable since it is mutable.

like image 40
Andrey Rusanov Avatar answered Oct 06 '22 00:10

Andrey Rusanov