GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing zetcode.com — Python hashing - hash function, hashable objects, __hash__, hashlib Python hashinglast modified October 30, 2026 Python 3.15
In this article we explain the hashing concept in Python. We cover hash
tables, the Hash tableHash tables are used to implement map and set data structures in many programming languages, such as C++, Java, and Python. Python uses hash tables for dictionaries and sets. A hash table is a collection of key-value pairs, where each key is unique. Hash tables offer efficient lookup, insert, and delete operations; on average, they take constant time regardless of the size of the table. HashingHashing is the process of using an algorithm to map data of any size to a value of a fixed size. This value is called a hash value or a hash. Hash values are computed with hash functions. A hash table uses the hash of a key to compute the slot where the key and its value are stored, so it does not have to search the whole table. Different keys may have the same hash value; this is called a collision. Therefore, after finding a slot by the hash, the table also compares the keys for equality. Python hashable
An object is hashable if it has a hash value which never
changes during its lifetime and if it can be compared to other objects. A
hashable object needs a
Note: Hashable objects which compare equal must have the
same hash value.
Hashability makes an object usable as a dictionary key and a set member,
because these data structures use the hash value internally. Python
immutable built-in objects are hashable; mutable containers (such as lists,
dictionaries, or sets) are not. Instances of user-defined classes are
hashable by default. They all compare unequal (except with themselves), and
their hash value is derived from their Python hash function
The builtin_hashables.py
print(hash(100))
print(hash(3.14))
print(hash('falcon'))
print(hash((1, 2, 3)))
print(hash(frozenset({1, 2, 3})))
print(hash(None))
The example prints the hash values of an integer, a float, a string, a
tuple, a frozen set, and $ python builtin_hashables.py 100 322818021289917443 214523777757570393 529344067295497451 -272375401224217160 4238894112 Hash randomizationThe hash values of strings and bytes are salted with a random value that is chosen when the interpreter starts. This protects web applications against denial-of-service attacks that send many keys with colliding hashes. The hash of a string is therefore constant within one run of a program, but it differs between runs. str_hash.py
print(hash('falcon'))
print(hash(b'falcon'))
print(hash(42))
We run the program several times. The hashes of the string and the bytes
object change; the hash of the integer does not. The
$ python str_hash.py -5709079237076841186 -5709079237076841186 42 $ python str_hash.py -4474288123343302275 -4474288123343302275 42 $ PYTHONHASHSEED=0 python str_hash.py 6462072199549027567 6462072199549027567 42 $ PYTHONHASHSEED=0 python str_hash.py 6462072199549027567 6462072199549027567 42 Hashes of numbersNumbers that compare equal have the same hash, even if they are of different types. numeric_hashes.py
print(hash(1), hash(1.0), hash(True))
print(hash(-1), hash(-2))
print(hash(2**61 - 1), hash(2**61))
vals = {1: 'int', 1.0: 'float', True: 'bool'}
print(vals)
Since $ python numeric_hashes.py
1 1 1
-2 -2
0 1
{1: 'bool'}
Unhashable objects
Mutable containers do not have a hash value. Calling unhashable.py
from collections.abc import Hashable
items = [[1, 2], {'a': 1}, {1, 2}, (1, [2, 3]), (1, 2), frozenset({1, 2})]
for item in items:
try:
print(f'{item!r:<18} {hash(item)}')
except TypeError as e:
print(f'{item!r:<18} {e}')
print(isinstance([1, 2], Hashable))
print(isinstance((1, 2), Hashable))
A list, a dictionary, and a set are unhashable. A tuple is hashable only if
all its elements are hashable. The $ python unhashable.py
[1, 2] unhashable type: 'list'
{'a': 1} unhashable type: 'dict'
{1, 2} unhashable type: 'set'
(1, [2, 3]) unhashable type: 'list'
(1, 2) -3550055125485641917
frozenset({1, 2}) -1826646154956904602
False
True
How a dictionary uses the hash
The following example shows when a dictionary calls the
dict_lookup.py
class Key:
def __init__(self, name):
self.name = name
def __hash__(self):
print(f'__hash__({self.name})')
return len(self.name)
def __eq__(self, other):
print(f'__eq__({self.name}, {other.name})')
return self.name == other.name
data = {}
data[Key('sky')] = 1
data[Key('owl')] = 2
data[Key('falcon')] = 3
print('lookup')
print(data[Key('owl')])
To provoke collisions, the hash of a key is the length of its name, so
$ python dict_lookup.py __hash__(sky) __hash__(owl) __eq__(sky, owl) __hash__(falcon) lookup __hash__(owl) __eq__(sky, owl) __eq__(owl, owl) 2 Default hash of custom objectsPython custom objects are hashable by default. Their hash is derived from their identity. custom_object.py
class User:
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
u1 = User('John Doe', 'gardener')
u2 = User('John Doe', 'gardener')
print(hash(u1))
print(hash(u2))
print(u1 == u2)
print(len({u1, u2}))
We create two instances of a $ python custom_object.py 8378367468696 8378367460477 False 2 Defining __eq__ only
In the second example, we implement a custom custom_object2.py
class User:
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
def __eq__(self, other):
if not isinstance(other, User):
return NotImplemented
return (self.name, self.occupation) == (other.name, other.occupation)
u1 = User('John Doe', 'gardener')
u2 = User('John Doe', 'gardener')
print(u1 == u2)
print(User.__hash__)
try:
users = {u1, u2}
except TypeError as e:
print(e)
Now the users compare equal. However, a class that defines
$ python custom_object2.py True None cannot use 'User' as a set element (unhashable type: 'User') Defining __eq__ and __hash__
In the third example, we implement both the custom_object3.py
class User:
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
def __eq__(self, other):
if not isinstance(other, User):
return NotImplemented
return (self.name, self.occupation) == (other.name, other.occupation)
def __hash__(self):
return hash((self.name, self.occupation))
def __repr__(self):
return f'User({self.name!r}, {self.occupation!r})'
u1 = User('John Doe', 'gardener')
u2 = User('John Doe', 'gardener')
u3 = User('Roger Roe', 'driver')
users = {u1, u2, u3}
print(users)
print(User('Roger Roe', 'driver') in users)
The $ python custom_object3.py
{User('Roger Roe', 'driver'), User('John Doe', 'gardener')}
True
Mutating a hashed objectThe hash of an object must not change while the object is stored in a set or used as a dictionary key. mutable_key.py
class User:
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
def __eq__(self, other):
if not isinstance(other, User):
return NotImplemented
return (self.name, self.occupation) == (other.name, other.occupation)
def __hash__(self):
return hash((self.name, self.occupation))
u1 = User('John Doe', 'gardener')
users = {u1}
print(u1 in users)
u1.occupation = 'programmer'
print(u1 in users)
print(any(u is u1 for u in users))
After we change the occupation, the hash of the user changes. The set
still keeps the object in the slot computed from the old hash, so the
membership test looks in the wrong slot and returns $ python mutable_key.py True False True Hashing with dataclasses
The dataclass_hash.py
from dataclasses import FrozenInstanceError, dataclass
@dataclass
class Point:
x: int
y: int
@dataclass(frozen=True)
class User:
name: str
occupation: str
print(Point.__hash__)
u1 = User('John Doe', 'gardener')
u2 = User('John Doe', 'gardener')
print(u1 == u2)
print(hash(u1) == hash(u2))
print({u1, u2})
try:
u1.occupation = 'programmer'
except FrozenInstanceError as e:
print(e)
The plain $ python dataclass_hash.py
None
True
True
{User(name='John Doe', occupation='gardener')}
cannot assign to field 'occupation'
Cryptographic hashes with hashlib
The hashlib_digest.py
import hashlib msg = 'an old falcon'.encode() print(hashlib.md5(msg).hexdigest()) print(hashlib.sha256(msg).hexdigest()) print(hashlib.sha3_256(msg).hexdigest()) print(hashlib.blake2b(msg, digest_size=16).hexdigest()) h = hashlib.sha256() h.update(b'an old ') h.update(b'falcon') print(h.hexdigest())
Hash functions work with bytes, so the string is encoded first. The
$ python hashlib_digest.py adf7c99320726d960ea9e8d817695e11 f3e6f76094b8eab3ec68bbed6e608f476e338eb4bc033242188d58c9e829fc5e c0426b8d94b30a5bc7dce521cb89507cd49b591d047ac5c82698e9e0281a0a15 d8e0f5ce933e07c324c91138e8021351 f3e6f76094b8eab3ec68bbed6e608f476e338eb4bc033242188d58c9e829fc5e Hashing a file
Since Python 3.11, the file_digest.py
import hashlib
with open('words.txt', 'w') as f:
f.write('sky\nblue\nfalcon\nowl\n')
with open('words.txt', 'rb') as f:
digest = hashlib.file_digest(f, 'sha256')
print(digest.name)
print(digest.hexdigest())
We compute the SHA-256 digest of a small text file. The
$ python file_digest.py sha256 c6deeb637a2d398a917805621867634a5169c0516eae153586e171ea780393cc $ sha256sum words.txt c6deeb637a2d398a917805621867634a5169c0516eae153586e171ea780393cc words.txt SourcePython hash function - Python documentation In this article we have covered hashing in Python. AuthorMy name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming. List all Python tutorials. |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |