2.2. OOP Hash
Used for quickly compare two objects
All objects compare unequal (except with themselves)
set()
elements has to be hashabledict()
keys has to be hashableUsed 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.2.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 equalUser-defined classes have
__eq__()
and__hash__()
methods by defaultIt also shouldn't change over the lifetime of the object
Generally you only implement it for immutable objects
class User:
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.2.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.2.3. Set Definition
>>> data = {'one', 'two', 'three'}
>>>
>>> data
{'two', 'one', 'three'}
>>>
>>> data
{'two', 'one', 'three'}
>>>
>>> data
{'two', 'one', 'three'}
>>>
>>> data
{'two', 'one', 'three'}
>>>
>>>
>>> hash('one')
8582268235435668451
>>>
>>> hash('two')
-6866033106748034186
>>>
>>> hash('three')
302666503681750062
class User:
def __init__(self, name):
self.name = name
mark = User('Mark Watney')
data = {mark, mark}
print(data)
# {<__main__.User object at 0x105be25b0>}
data = {User('Mark Watney'), User('Mark Watney')}
print(data)
# {<__main__.User object at 0x105be20a0>,
# <__main__.User object at 0x105be2040>}
class User:
def __init__(self, name):
self.name = name
def __hash__(self):
return hash(self.name)
def __eq__(self, other):
return hash(self) == hash(other)
mark = User('Mark Watney')
data = {mark, mark}
print(data)
# {<__main__.User object at 0x105bc77c0>}
data = {User('Mark Watney'), User('Mark Watney')}
print(data)
# {<__main__.User object at 0x105bc7700>}
2.2.4. Problem
>>> hash(-1) == hash(-2)
True
>>> hash(-1)
-2
>>>
>>> hash(-2)
-2
2.2.5. Use Case - 1
class User:
def __init__(self, name):
self.name = name
data = set()
mark = User('Mark Watney')
data.add(mark)
print(data)
# {<__main__.User object at 0x105bde070>}
data.add(mark)
print(data)
# {<__main__.User object at 0x105bde070>}
2.2.6. Use Case - 2
class User:
def __init__(self, name):
self.name = name
data = set()
data.add(User('Mark Watney'))
print(data)
# {<__main__.User object at 0x105bc7d00>}
data.add(User('Mark Watney'))
print(data)
# {<__main__.User object at 0x105bc7d00>,
# <__main__.User object at 0x105bc7e20>}
2.2.7. Use Case - 3
class User:
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(User('Mark Watney'))
print(data)
# {<__main__.User object at 0x105bde9d0>}
data.add(User('Mark Watney'))
print(data)
# {<__main__.User object at 0x105bde9d0>}
2.2.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'}