Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set the default subtitles language in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

Immutable vs. Hashable

Zarata on April 6, 2020

I’m fairly certain you’re trying to avoid going down a rabbit-hole complexity, but for me, the definition of “hashable” simply as “a type of object that you can call hash() on” feels incomplete, and almost circular. Sorry. Maybe you should add “beyond that, there be dragons here”?

James Uejio RP Team on April 11, 2020

Hi @Zarata yes good point I tried to simplify it in the video because this course is aimed to not require too much prior knowledge. Here is a good stack overflow answer for anyone who is curious what “Hashable” means: stackoverflow.com/questions/14535730/what-does-hashable-mean-in-python

joefol on June 24, 2020

Hi James, I started to watch your video today in the daytime and was fine to follow your video in the console. Now I’m picking up where I left of and its night time and I’m struggling to work it out (the blue on the black is impossible to work out) with the night light on, maybe a lighter background would help. Thanks

kiran on July 25, 2020

all immutable objects are hashable. but not all hashable objects are immutable.

can you give example for this statement.?

Bartosz Zaczyński RP Team on July 28, 2020

When you talk about Python’s built-in data types, then most of the immutable ones are hashable. These include tuples or frozen sets, for example:

# Immutable and hashable:
>>> hash(frozenset(['apple', 'banana', 'orange']))
-501384979540254233

It allows objects of these types to become dictionary keys or set members. On the other hand, instances of built-in mutable types, such as lists, dicts, or sets, are never hashable:

# Mutable but not hashable:
>>> hash(set(['apple', 'banana', 'orange']))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'

These can’t be used as dictionary keys, nor can they be added to a set, which both use the hash() function to calculate elements’ location in memory.

However, since the hash is derived from the object’s internal value, sometimes, even the immutable data types won’t be hashable in Python. When you add a mutable element, like a list, to an immutable collection, its collective value will no longer be immutable. Therefore, it won’t be hashable:

# Immutable but not hashable:
>>> hash(('apple', 'banana', 'orange', ['a list']))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

The tuple itself has a fixed set of elements, but one of them is mutable and can be modified without touching the tuple it belongs to.

To answer your question, I’m not aware of any built-in data types that are mutable and hashable at the same time, but user-defined classes have such properties by default:

>>> class MutableAndHashable:
...     def __init__(self, value):
...         self.value = value
...
>>> instance = MutableAndHashable(42)
>>> hash(instance)
8789535480438
>>> instance.value = 24
>>> hash(instance)
8789535480438
>>> hash(instance) == id(instance)
True

The default hash value of a class instance is the same as its identity. To disable “hashability” of a class, you can specify the __eq__() magic method that compares two instances:

>>> class MutableButNotHashable:
... 
...     def __init__(self, value):
...         self.value = value
...     
...     def __eq__(self, other):
...         if type(self) is type(other):
...             return self.value == obj.value
...         return False
... 
>>> instance = MutableButNotHashable(42)
>>> hash(instance)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    hash(instance)
TypeError: unhashable type: 'MutableButNotHashable'

However, when you override the __eq__() method, you almost certainly want to define the __hash__() one as well to adhere to the hash/eq contract. Otherwise, Python won’t use the default hash implementation anymore.

Also, a good hash function needs to have specific properties, such as avoiding so-called “collisions” or distributing elements evenly. But you don’t need to worry about it as long as you delegate to the built-in hash() function.

I hope this clears things up for you.

kiran on July 29, 2020

@Bartosz Zaczyński thanks for the update.

Become a Member to join the conversation.