2.3. Hash

  • Used for quickly compare two objects

  • All objects compare unequal (except with themselves)

  • set() elements has to be hashable

  • dict() keys has to be hashable

  • Used to quickly compare dictionary keys during a dictionary lookup

  • Since Python 3.11: siphash13 is added as a new internal hashing algorithms. It has similar security properties as siphash24 but it is slightly faster for long inputs. str, bytes, and some other types now use it as default algorithm for hash() [1]

class MyClass:
    def __hash__(self, *args, **kwargs):
        return 1234

    def __eq__(self, other):
        return hash(self) == hash(other)

2.3.1. Hash Method

  • hash(obj) ->  int

  • hash() returns the hash value of the object (if it has one)

  • __hash__ should return the same value for objects that are equal

  • User-defined classes have __eq__() and __hash__() methods by default

  • It also shouldn't change over the lifetime of the object

  • Generally you only implement it for immutable objects

class Astronaut:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname

    def __hash__(self, *args, **kwargs):
        firstname = hash(self.firstname)
        lastname = hash(self.lastname)
        return hash(firstname + lastname)

    def __eq__(self, other):
        return hash(self) == hash(other)

2.3.2. Examples

dict() keys has to be hashable:

data = {}

data[1] = 'whatever'
data[1.1] = 'whatever'
data['a'] = 'whatever'
data[True] = 'whatever'
data[False] = 'whatever'
data[None] = 'whatever'

data[(1,2)] = 'whatever'

data[[1,2]] = 'whatever'
# Traceback (most recent call last):
# TypeError: unhashable type: 'list'

data[{1,2}] = 'whatever'
# Traceback (most recent call last):
# TypeError: unhashable type: 'set'

data[frozenset({1,2})] = 'whatever'

data[{'a':1}] = 'cokolwiek'
# Traceback (most recent call last):
# TypeError: unhashable type: 'dict'

set() elements must be hashable:

{1, 1, 2}
# {1, 2}

{1, 1.1, 'a'}
# {1, 1.1, 'a'}

{'a', (1, 2)}
# {'a', (1, 2)}

2.3.3. Set Definition

class Astronaut:
    def __init__(self, name):
        self.name = name


mark = Astronaut('Mark Watney')
data = {mark, mark}
print(data)
# {<__main__.Astronaut object at 0x105be25b0>}

data = {Astronaut('Mark Watney'), Astronaut('Mark Watney')}
print(data)
# {<__main__.Astronaut object at 0x105be20a0>,
#  <__main__.Astronaut object at 0x105be2040>}
class Astronaut:
    def __init__(self, name):
        self.name = name

    def __hash__(self):
        return hash(self.name)

    def __eq__(self, other):
        return hash(self) == hash(other)


mark = Astronaut('Mark Watney')
data = {mark, mark}
print(data)
# {<__main__.Astronaut object at 0x105bc77c0>}

data = {Astronaut('Mark Watney'), Astronaut('Mark Watney')}
print(data)
# {<__main__.Astronaut object at 0x105bc7700>}

2.3.4. Problem

>>> hash(-1) == hash(-2)
True
>>> hash(-1)
-2
>>>
>>> hash(-2)
-2

2.3.5. Use Case - 0x01

class Astronaut:
    def __init__(self, name):
        self.name = name


data = set()
mark = Astronaut('Mark Watney')

data.add(mark)
print(data)
# {<__main__.Astronaut object at 0x105bde070>}

data.add(mark)
print(data)
# {<__main__.Astronaut object at 0x105bde070>}

2.3.6. Use Case - 0x02

class Astronaut:
    def __init__(self, name):
        self.name = name


data = set()

data.add(Astronaut('Mark Watney'))
print(data)
# {<__main__.Astronaut object at 0x105bc7d00>}

data.add(Astronaut('Mark Watney'))
print(data)
# {<__main__.Astronaut object at 0x105bc7d00>,
#  <__main__.Astronaut object at 0x105bc7e20>}

2.3.7. Use Case - 0x03

class Astronaut:
    def __init__(self, name):
        self.name = name

    def __hash__(self):
        return hash(self.name)

    def __eq__(self, other):
        return hash(self) == hash(other)


data = set()

data.add(Astronaut('Mark Watney'))
print(data)
# {<__main__.Astronaut object at 0x105bde9d0>}

data.add(Astronaut('Mark Watney'))
print(data)
# {<__main__.Astronaut object at 0x105bde9d0>}

2.3.8. Hashable

key = list([1, 2, 3])
hash(key)
# Traceback (most recent call last):
# TypeError: unhashable type: 'list'
class list(list):
    def __hash__(self):
        return 0

key = list([1, 2, 3])
hash(key)
0
data = {}

key = list([1,2,3])
data[key] = 'whatever'
# Traceback (most recent call last):
# TypeError: unhashable type: 'list'

class list(list):
    def __hash__(self):
        return 0

data[key] = 'whatever'
data
# {[1, 2, 3]: 'whatever'}

2.3.9. References