Hashmaps in Python: Master Implementation and Use Cases

William ImohWilliam Imoh

Hashmaps in Python explained

If you have ever built applications as a Python developer that support searching for a username in a database, counting items in a list, or caching an API response, you’ve probably used a hashmap directly or through one of its implementations.

Hashmaps are everywhere and power many parts of modern programming languages. They make data retrieval fast, support caching layers that improve performance, and help you write code that stays clean and efficient. In Python, the dictionary data type acts as the default hashmap for data storage. This gives you a powerful and efficient data structure without dealing with low-level memory details or manual hashing.

In this guide, you will learn how Python hashmaps work under the hood, how to use them effectively, and where they shine in real projects.

What is a hashmap in Python?

A hashmap is a data structure that stores information as key-value pairs. Each unique key maps to exactly one value, which allows for fast lookups. Instead of searching through items with the same input one by one, a hashmap jumps straight to the value you want by using a hash function.

A hash function is a mathematical operation that converts a key into a number. This number determines where the value is stored in memory, which explains why lookups are so fast. So instead of scanning every item like you would with a list, Python goes directly to the correct location, ensuring the same output for the same input. This process is essential for retrieving data quickly.

Hashmap in Python

Below is an example of a hashmap in Python using a dictionary:

python
user_data = {    "user_123": {"name": "Alice", "email": "alice@example.com"},    "user_456": {"name": "Bob", "email": "bob@example.com"},    "user_789": {"name": "Charlie", "email": "charlie@example.com"}}# Fast lookup - goes directly to the valueprint(user_data["user_456"])  # {'name': 'Bob', 'email': 'bob@example.com'}

Under the hood, when you create a hash map that stores key-value pair, Python does the following:

  1. It calculates the hash of each key using the built-in hash() function.

  2. It uses that hash to determine which bucket to place the value in.

  3. Before storing the value, it checks whether the bucket is already occupied. If it is, which is known as a collision, Python probes for the next available bucket following a defined pattern.

How a hashmap works

Buckets, hash function, collisions, and why they matter

A bucket is simply a position in the internal storage array. You can think of it like a mailbox, where each key gets a mailbox number based on its hash. Every time you insert a key, Python computes hash(key) and uses that value to decide where the key should go.

This works well when each key lands in a unique bucket. Things get more interesting when two different keys map to the same bucket. This situation is called a collision.

No collision vs. collision in hashmap

A collision does not mean your data is lost. Python uses a strategy called open addressing with probing to locate the next available bucket. It keeps probing until it finds a free spot. This approach keeps all entries in a single compact array. In contrast, many other languages use separate chaining, where each bucket points to an external linked list of key-value pairs that share the same bucket.

As a dictionary grows, collisions could become frequent if Python did not manage the size of its internal array. When the dictionary reaches a certain load factor, Python resizes the hash table by allocating a larger one and rehashing the entries. This happens infrequently and helps keep operations fast over time.

Collisions also matter for security. If many keys produce similar hash patterns, an attacker could deliberately trigger collisions and slow down your program. Python mitigates this by using randomized hash functions for strings, which makes such attacks significantly harder.

Implementing hashmaps in Python

Python dictionaries are the most convenient way to work with hashmaps, so you do not need to worry about implementing hash functions or managing buckets yourself. The language handles all of that complexity while giving you a clean and intuitive interface. Let’s walk through the core operations you will use in everyday coding to create, modify, and retrieve values quickly.

Creating a hashmap with a dictionary

You have several ways to create a dictionary in Python. The most common approach uses curly braces {}:

python
inventory = {    "apples": 50,    "bananas": 30,    "oranges": 25}# Empty dictionarystorage = {}

Another handy option is using Python’s built-in dict() constructor. This creates a hashmap by taking keyword arguments or iterable key-value pairs and internally hashing each key before storing it in the dictionary:

python
# Using the dict() constructorconfig = dict(host="localhost", port=8080, debug=True)

It is important to note that dictionary keys must be unique. If you define duplicate keys, Python does not raise an error. Instead, it keeps the last occurrence of the particular key and discards the earlier one:

python
inventory = {    "apples": 50,    "bananas": 30,    "oranges": 25,    "oranges": 37,}print(inventory) # {'apples': 50, 'bananas': 30, 'oranges': 37}

Searching a hashmap

Beyond creating a hashmap, you will often need to search for values stored inside it. To retrieve a value, specify the key inside square brackets, and Python returns the corresponding value:

python
inventory = {    "apples": 50,    "bananas": 30,    "oranges": 25}# key existsprint(inventory["oranges"]) # 25 

If you try to access a nonexistent key, Python raises a KeyError. For example, accessing inventory["pineapple"] results in the following error:

python
Traceback (most recent call last):  File "main.py", line 9, in <module>    print(inventory["pineapple"])KeyError: 'pineapple'
Searching hashmaps decision flow

In production code, the get() method is often a better choice because it prevents crashes when a key is missing. If the key does not exist, get() returns None by default instead of raising an error:

python
inventory.get("pineapple") # None

You can also provide a fallback value if you want a custom default.

Adding to a hashmap

You can add new entries to a hashmap by assigning a value to a new key:

python
inventory["lemons"] = 55print(inventory) # {'apples': 50, 'bananas': 30, 'oranges': 25, 'lemons': 55}

Updating a hashmap

Updating an existing key uses the same syntax as adding a new one. If the key already exists, assigning a new value will update the existing entry with the new value; if the key does not exist, it will be created.

python
inventory["apples"] = 30print(inventory) # {'apples': 30, 'bananas': 30, 'oranges': 25, 'lemons': 55}

Deleting values from a hashmap

To remove a key value pair from a hashmap, use the del keyword with the specific key:

python
del inventory["apples"]print(inventory) # {'bananas': 30, 'oranges': 25}

Python also provides the clear() method, which removes all key value pairs from the dictionary:

python
inventory.clear()print(inventory) # {}

Useful dictionary methods

Beyond basic create, read, update, and delete operations, Python dictionaries include several helper methods that make working with hashmaps easier.

The items() method returns a view of all key-value pairs:

python
items = inventory.items()print(items) # dict_items([('apples', 50), ('bananas', 30), ('oranges', 25)])

The keys() method returns a view containing all the keys:

python
keys = inventory.keys()print(keys) # dict_keys(['apples', 'bananas', 'oranges'])

The values() method helps access values in a hashmap:

python
values = inventory.values()print(values) # dict_values([50, 30, 25])

While Python dictionaries provide a powerful and efficient built-in implementation of hashmaps, they are not the only way to model key-value mappings in Python. In some situations, factors like ordering rules, default values, or specific performance tradeoffs may call for alternative approaches. The next section explores other ways to create and work with hashmap-like structures in Python.

Alternative ways to create hashmaps in Python

Using {} to create a dictionary often feels like second nature in Python, until it no longer fits what you need. You might be transforming two lists into key-value pairs, initializing default values, or building a hashmap on the fly from more complex data. Python provides built-in functions and tools for all of these scenarios. Below are several alternative hashmap implementations you can use, depending on your use case.

collections.defaultdict

A defaultdict automatically creates a default value for missing keys. This removes the need for manual existence checks and helps you avoid KeyError exceptions.

python
from collections import defaultdict# Grouping items by categoryproducts_by_category = defaultdict(list)products = [    ("Electronics", "Laptop"),    ("Electronics", "Phone"),    ("Clothing", "Shirt"),    ("Electronics", "Tablet"),    ("Clothing", "Pants")]# Loop through each (category, product) pair and # if the key does not exist create an empty list for itfor category, product in products:    products_by_category[category].append(product)print(dict(products_by_category))# {'Electronics': ['Laptop', 'Phone', 'Tablet'], 'Clothing': ['Shirt', 'Pants']}

collections.Counter

Counter is a specialized hashmap designed for counting hashable objects. It is commonly used for analytics, frequency tracking, and quick summaries.

python
from collections import Counter# Analyzing page viewspage_views = ["home", "about", "home", "contact", "home", "about", "home"]view_counts = Counter(page_views)print(view_counts)  # Counter({'home': 4, 'about': 2, 'contact': 1})print(view_counts.most_common(2))  # [('home', 4), ('about', 2)]

collections.OrderedDict

OrderedDict explicitly preserves insertion order. While regular dictionaries maintain insertion order starting from Python 3.7, you may still see OrderedDict in legacy code or in cases where its specialized methods, such as move_to_end(), are useful.

python
from collections import OrderedDictod = OrderedDict()od["a"] = 1od["b"] = 2

collections.ChainMap

ChainMap groups multiple dictionaries into a single logical hashmap. This works well for layered configurations where values can be overridden by higher priority scopes.

python
from collections import ChainMapdefaults = {"debug": False}env = {"debug": True}config = ChainMap(env, defaults)

types.MappingProxyType

MappingProxyType provides a read-only view of a dictionary. It is useful when you want to expose configuration or shared data while preventing accidental mutation.

python
from types import MappingProxyTyped = {"a": 1}readonly = MappingProxyType(d)

shelve

shelve offers a simple way to create a persistent new key-value pair backed by disk storage. It is helpful when you need lightweight persistence without introducing a full database system.

python
import shelvewith shelve.open("data.db") as db:    db["x"] = 10

Now that you have seen several ways to create hashmap-like structures in Python, the next question is when to use them. Hashmaps show up everywhere in real-world Python programs and often solve problems more cleanly than other data structures. The next section explores practical applications of hashmaps and how they fit into everyday Python development.

Practical applications of hashmaps

Hashmaps are one of those data structures you end up using all the time, even if you do not always notice it. Their ability to store data and retrieve data quickly makes them useful across many real-world scenarios. Below are some common and practical use cases. 

Caching and memoization

Hashmaps are widely used for storing data that is expensive to compute or fetch. The idea is simple. Once a value is calculated, it is stored in a hashmap using a unique key. The next time that value is needed, it can be retrieved instantly instead of being recomputed.

Frequency counting and analytics

Counting how often something occurs is a very common task in data science, analytics, and data processing. Hashmaps make this straightforward by mapping each item to its count. For example, you can count word occurrences in a document, track how often an event happens, or summarize user actions in an application.

Database indexing and lookups

At a high level, many database indexes behave like hashmaps. They allow the database to locate records quickly based on a key such as an ID, email, or username, without scanning every row.

In application code, hashmaps can also act as lightweight in-memory indexes. By mapping record IDs to objects, you can access data instantly. This pattern is common in ORMs, in-memory databases, and caching layers.

Grouping and aggregation

Hashmaps are a natural fit for grouping related data. You can use a key to represent a category and store all related values under that key. Examples include grouping orders by customer ID, log entries by date, or products by category. As you iterate over the data, the hashmap helps organize and aggregate results efficiently without complex data structures.

Configuration management

Configuration settings are often stored as key-value pairs, which makes hashmaps an ideal choice. They allow you to load settings from files, environment variables, or remote services and access them quickly throughout your application.

Common errors and best practices

Hashmaps are powerful and easy to use, but they also come with a few common pitfalls. Understanding these mistakes and following best practices can help you avoid bugs, improve performance, and write cleaner code.

Using mutable objects as keys

One common mistake is using mutable objects, such as lists or dictionaries, as hashmap keys. Hashmap keys must be immutable and hashable, because if a key changes after being added, the hashmap may no longer be able to locate it.

Best practice: Use immutable types like strings, numbers, or tuples as keys for reliable lookups. If you need a complex key, make sure it is immutable and has a stable hash value.

Overusing hashmaps

Hashmaps are fast, but they are not always the right tool. Using them where a list, set, or simple variable would work can introduce unnecessary complexity and memory overhead.

Best practice: Choose the simplest data structure that fits the problem. Use hashmaps when you truly need fast key-based lookups or mappings.

Ignoring performance and memory costs

Although hashmaps offer average constant-time operations, they consume more memory than some alternatives. Very large hashmaps or deeply nested dictionaries can also affect performance.

Best practice: Be mindful of size and usage patterns. Clean up unused entries, avoid excessive nesting, and consider whether a different structure or approach would be more efficient for your use case.

Assuming hashmaps are ordered

Don’t assume that hashmaps will always maintain order. While modern Python dictionaries preserve insertion order, this behavior should not be relied on for algorithmic correctness unless order is explicitly part of the design.

Best practice: If ordering matters to your logic, make it explicit. Use ordered data structures or sort keys when needed instead of relying on implicit behavior.

Not handling missing keys properly

Accessing a non-existent key can raise errors or lead to unexpected behavior. This often happens when working with user input, external data, or incomplete datasets.

Best practice: Use safe access patterns such as get(), defaultdict, or explicit checks before accessing keys. These approaches make your code more robust.

Wrapping up

Hashmaps are one of those foundational concepts that you'll use constantly once you understand them. Python's dictionary data implementation makes them accessible without sacrificing performance, which is why they show up in everything from simple scripts to large-scale distributed systems.

If you want more hands-on practice with hashmaps, chat with the AI tutor, start with the prompt below:

You can also check out the Python roadmap for a more robust and structured learning path.

Join the Community

roadmap.sh is the 6th most starred project on GitHub and is visited by hundreds of thousands of developers every month.

Rank 6th out of 28M!

350K

GitHub Stars

Star us on GitHub
Help us reach #1

+90kevery month

+2.8M

Registered Users

Register yourself
Commit to your growth

+2kevery month

45K

Discord Members

Join on Discord
Join the community

RoadmapsGuidesFAQsYouTube

roadmap.shby@kamrify

Community created roadmaps, best practices, projects, articles, resources and journeys to help you choose your path and grow in your career.

© roadmap.sh·Terms·Privacy·

ThewNewStack

The top DevOps resource for Kubernetes, cloud-native computing, and large-scale development and deployment.