This module proposes hashable version of the mutable containers list, dict and set, called respectively hlist, hdict and hset.

After one object has been hashed, it becomes not mutable and raises a ValueError if a method which changes the object (let call a mutation such a method) is invoqued. The object can be then un-hashed by calling unhash on it so that it becomes mutable again. Notice that this may cause troubles if the object is stored in a set or dict which uses its hashcode to locate it. Notice also that hashable containers cannot be hashed if they contain non hashable objects.

>>> l = hlist(range(5))
>>> l
hlist([0, 1, 2, 3, 4])
>>> _ = hash(l)
>>> l.append(5)
Traceback (most recent call last):
...
ValueError: hashed 'hlist' object is not mutable
>>> unhash(l)
>>> l.append(5)
>>> l
hlist([0, 1, 2, 3, 4, 5])

Testing if a hlist is in a set, dict, hset or hdict causes its hashing. If this is not desirable, you should either compensate with a call to unhash, or test if a copy is in the set:

>>> s = set()
>>> s.add(list(range(4)))
Traceback (most recent call last):
...
TypeError: ...
>>> s.add(hlist(range(4)))
>>> l = hlist(range(3))
>>> l in s
False
>>> l.append(3)
Traceback (most recent call last):
...
ValueError: hashed 'hlist' object is not mutable
>>> unhash(l)
>>> l.append(3)
>>> l[:] in s
True
>>> l.append(4)

Function unhash

def unhash (obj) :

Make the object mutable again. This should be used with caution, especially if the object is stored in a dict or a set.

>>> l = hlist(range(3))
>>> _ = hash(l)
>>> l.append(3)
Traceback (most recent call last):
...
ValueError: hashed 'hlist' object is not mutable
>>> unhash(l)
>>> l.append(3)
Call API

Class hlist

class hlist (list) :

Hashable lists. They support all standard methods from list.

>>> l = hlist(range(5))
>>> l
hlist([0, 1, 2, 3, 4])
>>> l.append(5)
>>> l
hlist([0, 1, 2, 3, 4, 5])
>>> _ = hash(l)
>>> l.append(6)
Traceback (most recent call last):
...
ValueError: hashed 'hlist' object is not mutable
>>> unhash(l)
>>> l.append(6)

Class hdict

class hdict (dict) :

Hashable dictionnaries. They support all standard methods from dict.

>>> l = hlist(range(5))
>>> d = hdict([(l, 0)])
>>> d
hdict({hlist([0, 1, 2, 3, 4]): 0})
>>> l in d
True
>>> [0, 1, 2, 3, 4] in d
Traceback (most recent call last):
...
TypeError: ...
>>> hlist([0, 1, 2, 3, 4]) in d
True
>>> d[hlist([0, 1, 2, 3, 4])]
0
>>> l.append(5)
Traceback (most recent call last):
...
ValueError: hashed 'hlist' object is not mutable
>>> _ = hash(d)
>>> d.pop(l)  # any mutation would produce the same error
Traceback (most recent call last):
...
ValueError: hashed 'hdict' object is not mutable
>>> unhash(d)
>>> d.pop(l)
0

Class hset

class hset (set) :

Hashable sets. They support all standard methods from set.

>>> s = hset()
>>> l = hlist(range(5))
>>> s.add(l)
>>> s
hset([hlist([0, 1, 2, 3, 4])])
>>> l in s
True
>>> [0, 1, 2, 3, 4] in s
Traceback (most recent call last):
...
TypeError: ...
>>> hlist([0, 1, 2, 3, 4]) in s
True
>>> l.append(5)
Traceback (most recent call last):
...
ValueError: hashed 'hlist' object is not mutable
>>> _ = hash(s)
>>> s.discard(l)  # any mutation would produce the same error
Traceback (most recent call last):
...
ValueError: hashed 'hset' object is not mutable
>>> unhash(s)
>>> s.discard(l)