Free Python Dictionary Methods Cheat Sheet Online — Interactive Reference with Examples

·

Try the tool first:

Open the Interactive Python Dictionary Methods Cheat Sheet

40+ methods, real-time search, category filtering, one-click copy. 100% client-side, no signup.

Python dictionaries are the most versatile data structure in the language. Every Python developer uses them dozens of times per day. Yet even experienced developers occasionally pause to remember: Does get() raise an error? What's the difference between update() and |=? How do I merge dicts without mutating the originals? What's the fastest way to count frequencies?

This comprehensive guide covers every Python dictionary method, operator, and common pattern you need to know. Each section includes practical code examples you can copy and run immediately. By the end, you'll know dictionaries inside and out — and you'll have a free interactive cheat sheet bookmarked for quick reference.

What Are Python Dictionaries?

A Python dictionary is an unordered, mutable mapping of hashable keys to arbitrary values. Dictionaries are implemented as hash tables in CPython, which gives them O(1) average-case time complexity for lookups, insertions, and deletions. They are defined with curly braces or the dict() constructor.

# Creating dictionaries
empty = {}
empty2 = dict()

# Literal syntax
person = {"name": "Alice", "age": 30, "city": "NYC"}

# From keyword arguments
person2 = dict(name="Bob", age=25, city="LA")

# From a list of tuples
items = [("a", 1), ("b", 2), ("c", 3)]
d = dict(items)

# From two parallel iterables with zip()
keys = ["x", "y", "z"]
values = [10, 20, 30]
d = dict(zip(keys, values))

# Fromkeys — initialize with default value
keys = ["read", "write", "execute"]
perms = dict.fromkeys(keys, False)
# perms → {'read': False, 'write': False, 'execute': False}

Key Requirements: Hashability

Dictionary keys must be hashable. Immutable built-in types — strings, numbers, tuples (if elements are hashable), frozensets — are hashable. Mutable types like lists, dictionaries, and sets cannot be used as keys.

# Valid keys
{"name": "Alice"}           # string key
{42: "answer"}              # int key
{(1, 2): "point"}           # tuple key (elements are hashable)

# Invalid keys — TypeError
{[1, 2]: "list"}            # list is unhashable
{{"a": 1}: "dict"}          # dict is unhashable

Performance note: Dictionaries in CPython 3.6+ maintain insertion order as an implementation detail, and this became a language guarantee in Python 3.7+. This means iterating over a dict yields keys in the order they were inserted.

Accessing Values

Python provides multiple ways to retrieve values from a dictionary. Choosing the right method prevents KeyError exceptions and makes your code more robust.

Bracket Notation — d[key]

The most direct way to access a value. It raises KeyError if the key does not exist. Use this when you are certain the key is present.

d = {"name": "Alice", "age": 30}
name = d["name"]     # "Alice"
age = d["age"]       # 30

# Missing key raises KeyError
city = d["city"]     # KeyError: 'city'

get() — Safe Access with Default

d.get(key, default) returns the value for key if it exists, otherwise default (or None if default is omitted). It never raises KeyError.

d = {"name": "Alice", "age": 30}

city = d.get("city")           # None
city = d.get("city", "NYC")    # "NYC"
name = d.get("name", "Unknown") # "Alice" (default ignored)

# Common pattern: counting with get()
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
counts = {}
for w in words:
    counts[w] = counts.get(w, 0) + 1
# counts → {'apple': 3, 'banana': 2, 'cherry': 1}

setdefault() — Get or Create

d.setdefault(key, default) returns the value for key if it exists. If not, it inserts key with default and returns default. This is useful for lazy initialization.

d = {"name": "Alice"}

# Key exists — returns existing value, no change
age = d.setdefault("age", 25)   # age = 30 if "age" was 30

# Key missing — inserts and returns default
city = d.setdefault("city", "NYC")
# d → {"name": "Alice", "city": "NYC"}

# Grouping pattern
emails = [
    ("sales", "a@example.com"),
    ("support", "b@example.com"),
    ("sales", "c@example.com"),
]
groups = {}
for dept, email in emails:
    groups.setdefault(dept, []).append(email)
# groups → {'sales': ['a@...', 'c@...'], 'support': ['b@...']}

collections.defaultdict — Automatic Defaults

For automatic default value generation (especially mutable defaults), collections.defaultdict is cleaner than setdefault(). Pass a factory function like list, set, int, or dict.

from collections import defaultdict

# Automatic list
dd = defaultdict(list)
dd["fruits"].append("apple")
dd["fruits"].append("banana")
# dd → defaultdict({'fruits': ['apple', 'banana']})

# Automatic int (for counting)
counts = defaultdict(int)
for w in ["apple", "banana", "apple"]:
    counts[w] += 1
# counts → defaultdict({'apple': 2, 'banana': 1})

# Automatic set (for deduplication)
unique = defaultdict(set)
unique["tags"].add("python")
unique["tags"].add("python")  # ignored — set deduplicates
# unique → defaultdict({'tags': {'python'}})

Rule of thumb: Use d[key] when the key must exist (fail fast). Use d.get() for optional values with a simple default. Use setdefault() for lazy initialization. Use defaultdict when you need automatic factory-generated defaults, especially for mutable types.

Adding and Updating Elements

Direct Assignment

Assigning to a key inserts it if missing, or updates the value if present. This is the simplest and fastest way to add or update a single key.

d = {"name": "Alice"}
d["age"] = 30        # Insert new key
d["name"] = "Bob"    # Update existing key
# d → {'name': 'Bob', 'age': 30}

update() — Merge Another Mapping

d.update(other) merges key-value pairs from other into d. Existing keys are overwritten. other can be a dictionary, an iterable of key-value pairs, or keyword arguments.

d = {"a": 1, "b": 2}

# From another dict
d.update({"b": 20, "c": 3})
# d → {'a': 1, 'b': 20, 'c': 3}

# From iterable of tuples
d.update([("d", 4), ("e", 5)])

# From keyword arguments
d.update(f=6, g=7)
# d → {'a': 1, 'b': 20, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7}

|= Operator — In-Place Merge (Python 3.9+)

The |= operator updates the left dictionary in-place with key-value pairs from the right. It is equivalent to update() but can be used in expressions.

d = {"a": 1, "b": 2}
d |= {"b": 20, "c": 3}
# d → {'a': 1, 'b': 20, 'c': 3}

Removing Elements

del — Delete by Key

The del statement removes a key-value pair. It raises KeyError if the key does not exist. del is a statement, not a method — it does not return a value.

d = {"a": 1, "b": 2, "c": 3}
del d["b"]
# d → {'a': 1, 'c': 3}

# Safe deletion with check
if "z" in d:
    del d["z"]

pop() — Remove and Return

d.pop(key, default) removes key and returns its value. If the key is missing and no default is provided, it raises KeyError. With a default, it returns the default without modifying the dictionary.

d = {"a": 1, "b": 2, "c": 3}
val = d.pop("b")           # val = 2; d → {'a': 1, 'c': 3}
val = d.pop("z", None)     # val = None; d unchanged

# Common pattern: extract and process
config = {"debug": True, "timeout": 30}
debug = config.pop("debug", False)
# Process with debug flag, config no longer contains it

popitem() — Remove and Return Arbitrary Item

d.popitem() removes and returns the last inserted key-value pair as a tuple (LIFO order). In Python 3.7+, this is guaranteed to be the most recently added item. Raises KeyError if the dictionary is empty.

d = {"a": 1, "b": 2, "c": 3}
item = d.popitem()
# item → ('c', 3); d → {'a': 1, 'b': 2}

# LIFO stack behavior
stack = {}
stack["first"] = 1
stack["second"] = 2
k, v = stack.popitem()   # ('second', 2)

clear() — Remove All Items

d.clear() removes all key-value pairs, leaving an empty dictionary. It is more efficient than repeatedly calling popitem() or reassigning d = (which creates a new object).

d = {"a": 1, "b": 2}
d.clear()
# d → {}

# clear() vs reassigning
d2 = d.copy()
d.clear()       # d2 still references original (now empty)
# vs
d = {}          # d2 still references the old dict object

Querying and Inspecting

keys(), values(), items()

These methods return view objects that reflect the dictionary's current state dynamically. They are not copies — changes to the dictionary are visible in the views.

d = {"a": 1, "b": 2, "c": 3}

k = d.keys()       # dict_keys(['a', 'b', 'c'])
v = d.values()     # dict_values([1, 2, 3])
items = d.items()  # dict_items([('a', 1), ('b', 2), ('c', 3)])

# Views are dynamic
k  # dict_keys(['a', 'b', 'c'])
d["d"] = 4
k  # dict_keys(['a', 'b', 'c', 'd'])  — updated!

# Iteration
for key in d.keys():
    print(key)

for value in d.values():
    print(value)

for key, value in d.items():
    print(f"{key} = {value}")

Membership Testing — in

The in operator tests key membership (not values). It uses the hash table for O(1) average-case lookup.

d = {"a": 1, "b": 2}
"a" in d       # True  (key membership)
1 in d         # False (values are not checked)
"z" not in d   # True

# Check values with .values()
1 in d.values()  # True

len() and bool()

d = {"a": 1, "b": 2}
len(d)     # 2
bool(d)    # True

empty = {}
len(empty)   # 0
bool(empty)  # False

# Idiomatic emptiness check
if d:
    print("Dictionary has items")
if not empty:
    print("Dictionary is empty")

View object surprise: View objects do not support indexing. You cannot do d.keys()[0]. Convert to a list if you need indexing: list(d.keys())[0]. However, this is O(n) and creates a copy — prefer iteration or next(iter(d)) for the first key.

Merging Dictionaries

Python offers multiple ways to combine dictionaries. The right choice depends on whether you want a new dictionary or in-place modification, and which Python version you are using.

| Operator — New Merged Dict (Python 3.9+)

The | operator creates a new dictionary containing all key-value pairs from both operands. The right-hand dictionary's values win on key collisions.

d1 = {"a": 1, "b": 2}
d2 = {"b": 20, "c": 3}

merged = d1 | d2
# merged → {'a': 1, 'b': 20, 'c': 3}
# d1 and d2 are unchanged

{**a, **b} — Unpacking Merge

Dictionary unpacking with ** works in Python 3.5+. It creates a new dictionary by unpacking both operands. Rightmost values win on collisions.

d1 = {"a": 1, "b": 2}
d2 = {"b": 20, "c": 3}

merged = {**d1, **d2}
# merged → {'a': 1, 'b': 20, 'c': 3}

# Merge more than two
merged = {**d1, **d2, **{"d": 4}}

update() and |= — In-Place Merge

Both modify the left dictionary. See the "Adding and Updating" section for details.

Comparison Table: Merge Methods

Method Returns Modifies Original Python Version When to Use
d1 | d2 New dict No 3.9+ New merged dict, clean syntax
{**d1, **d2} New dict No 3.5+ New merged dict, older Python
d1.update(d2) None Yes (d1) All In-place merge, method call
d1 |= d2 None Yes (d1) 3.9+ In-place merge, operator syntax

Dictionary Comprehensions

Dictionary comprehensions provide a concise, readable way to create dictionaries from iterables. They are generally faster than equivalent for-loops.

Basic Syntax

# Squares mapping
{x: x**2 for x in range(5)}
# → {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# From two lists
keys = ["a", "b", "c"]
values = [1, 2, 3]
{k: v for k, v in zip(keys, values)}
# → {'a': 1, 'b': 2, 'c': 3}

Filtered Comprehensions

# Only even keys
{x: x**2 for x in range(10) if x % 2 == 0}
# → {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}

# Filter by value from existing dict
d = {"a": 1, "b": 20, "c": 3, "d": 40}
{k: v for k, v in d.items() if v > 10}
# → {'b': 20, 'd': 40}

Conditional Expressions

# Categorize numbers
nums = [1, 2, 3, 4, 5]
{x: "even" if x % 2 == 0 else "odd" for x in nums}
# → {1: 'odd', 2: 'even', 3: 'odd', 4: 'even', 5: 'odd'}

# Normalize values (cap at 100)
scores = {"Alice": 95, "Bob": 120, "Carol": 88}
{k: (v if v <= 100 else 100) for k, v in scores.items()}
# → {'Alice': 95, 'Bob': 100, 'Carol': 88}

Nested and Advanced Patterns

# Invert a dictionary (values become keys)
d = {"a": 1, "b": 2, "c": 3}
{v: k for k, v in d.items()}
# → {1: 'a', 2: 'b', 3: 'c'}

# Swap keys and values with transformation
d = {"Alice": 30, "Bob": 25}
{v: k.upper() for k, v in d.items()}
# → {30: 'ALICE', 25: 'BOB'}

# Group lengths by first letter
words = ["apple", "apricot", "banana", "cherry"]
{w[0]: len(w) for w in words}
# → {'a': 7, 'b': 6, 'c': 6}  (last word wins for 'a')

Performance tip: Dictionary comprehensions run at C speed inside the interpreter and are typically 20-40% faster than equivalent for-loops. Use them whenever the logic fits on one readable line.

Common Patterns

Frequency Counting

The most common dictionary pattern. Count occurrences of items in an iterable.

from collections import Counter

words = ["apple", "banana", "apple", "cherry", "banana", "apple"]

# Using Counter (recommended)
counts = Counter(words)
# Counter({'apple': 3, 'banana': 2, 'cherry': 1})

# Manual with get()
counts = {}
for w in words:
    counts[w] = counts.get(w, 0) + 1

# Manual with setdefault()
counts = {}
for w in words:
    counts.setdefault(w, 0)
    counts[w] += 1

# Most common elements
counts.most_common(2)
# → [('apple', 3), ('banana', 2)]

Grouping

Group items by a common key. This pattern appears in data processing pipelines.

from collections import defaultdict

people = [
    {"name": "Alice", "dept": "Engineering"},
    {"name": "Bob", "dept": "Sales"},
    {"name": "Carol", "dept": "Engineering"},
]

# Group by department
by_dept = defaultdict(list)
for p in people:
    by_dept[p["dept"]].append(p["name"])
# → {'Engineering': ['Alice', 'Carol'], 'Sales': ['Bob']}

# Group by first letter
words = ["apple", "apricot", "banana", "cherry"]
by_letter = defaultdict(list)
for w in words:
    by_letter[w[0]].append(w)
# → {'a': ['apple', 'apricot'], 'b': ['banana'], 'c': ['cherry']}

Inverting a Dictionary

Swap keys and values. Be careful — values must be unique or you will lose data.

d = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in d.items()}
# → {1: 'a', 2: 'b', 3: 'c'}

# Handle duplicate values — group by value
from collections import defaultdict
d = {"a": 1, "b": 2, "c": 1}
inverted = defaultdict(list)
for k, v in d.items():
    inverted[v].append(k)
# → {1: ['a', 'c'], 2: ['b']}

Finding the Key with Maximum Value

scores = {"Alice": 95, "Bob": 87, "Carol": 92}

# Key with max value
best = max(scores, key=scores.get)
# → 'Alice'

# Key with min value
worst = min(scores, key=scores.get)
# → 'Bob'

# Get the actual max value
max_score = max(scores.values())
# → 95

Sorting by Value

scores = {"Alice": 95, "Bob": 87, "Carol": 92}

# Sort by value ascending
sorted(scores.items(), key=lambda x: x[1])
# → [('Bob', 87), ('Carol', 92), ('Alice', 95)]

# Sort by value descending
sorted(scores.items(), key=lambda x: x[1], reverse=True)
# → [('Alice', 95), ('Carol', 92), ('Bob', 87)]

# Convert back to dict (Python 3.7+ preserves order)
dict(sorted(scores.items(), key=lambda x: x[1], reverse=True))
# → {'Alice': 95, 'Carol': 92, 'Bob': 87}

Comparison Tables

d[key] vs d.get() vs d.setdefault()

Feature d[key] d.get(key, default) d.setdefault(key, default)
Missing key behavior Raises KeyError Returns default/None Inserts default, returns it
Modifies dictionary No No Yes (if key missing)
Use case Key must exist Safe read with fallback Lazy initialization
Performance O(1) O(1) O(1)
Example result d["x"] → KeyError d.get("x", 0) → 0 d.setdefault("x", 0) → 0, d now has "x"

update() vs | vs |= vs {**a, **b}

Feature update() | |= {**a, **b}
Returns None New dict None New dict
Modifies left operand Yes No Yes No
Python version All 3.9+ 3.9+ 3.5+
Accepts iterables Yes Dict only Dict only Dict only
Syntax style Method call Binary operator Augmented operator Literal unpacking

pop() vs del vs popitem()

Feature pop(key, default) del d[key] popitem()
Returns value Yes No Yes (key, value tuple)
Requires key Yes Yes No (removes last inserted)
Missing key behavior Returns default or KeyError KeyError KeyError (if empty)
Use case Remove known key, use value Delete known key LIFO stack pop

Performance Considerations

Understanding the time complexity of dictionary operations helps you write efficient code:

Operation Time Complexity Notes
d[key] (get)O(1) averageHash table lookup
d[key] = value (set)O(1) averageHash table insertion
del d[key]O(1) averageHash table deletion
key in dO(1) averageHash table membership
len(d)O(1)Stored internally
Iteration (keys/values/items)O(n)Visits all n items
d.copy()O(n)Shallow copy of all items
d | other (merge)O(n + m)n = len(d), m = len(other)
d.update(other)O(m)m = len(other)

Space complexity: Dictionaries use more memory than lists due to hash table overhead (typically 2-3x the space of a list of the same logical size). This tradeoff gives you O(1) lookups instead of O(n).

Common Gotchas and How to Avoid Them

1. Mutable Default Arguments with dict()

Never use a dictionary as a default argument. It evaluates once at function definition and is shared across all calls.

# WRONG
def add_item(key, value, d={}):
    d[key] = value
    return d

add_item("a", 1)  # {'a': 1}
add_item("b", 2)  # {'a': 1, 'b': 2} — same dict!

# CORRECT
def add_item(key, value, d=None):
    if d is None:
        d = {}
    d[key] = value
    return d

2. Modifying a Dictionary While Iterating

Adding or removing keys during iteration can raise RuntimeError or skip elements. Iterate over a copy of the keys instead.

# WRONG — RuntimeError in Python 3
d = {"a": 1, "b": 2, "c": 3}
for k in d:
    if d[k] < 2:
        del d[k]

# CORRECT — iterate over a copy of keys
for k in list(d.keys()):
    if d[k] < 2:
        del d[k]

# BETTER — dict comprehension
d = {k: v for k, v in d.items() if v >= 2}

3. Unhashable Keys

Lists and dictionaries cannot be used as keys. If you need composite keys, use tuples (which are hashable if their elements are hashable).

# WRONG
d = {[1, 2]: "point"}  # TypeError: unhashable type: 'list'

# CORRECT — use tuple
d = {(1, 2): "point"}  # OK

# For nested dict keys, serialize or use tuple of items
d = {tuple(sorted({"x": 1}.items())): "value"}

4. View Object Surprises

View objects reflect live dictionary state but do not support indexing. They also become invalid if the dictionary is resized during iteration (though iterating is safe if you only modify values for existing keys).

d = {"a": 1, "b": 2}
keys = d.keys()

# Cannot index
# keys[0]  # TypeError

# Safe: iterate and modify values
for k in d.keys():
    d[k] *= 2  # OK — keys unchanged

# Unsafe: add/remove during iteration
for k in d.keys():
    d["c"] = 3  # RuntimeError: dictionary changed size

5. Shallow Copy Gotchas

d.copy(), dict(d), and {**d} all create shallow copies. Nested mutable objects are shared.

import copy

d = {"a": [1, 2], "b": 3}
c = d.copy()

c["b"] = 99       # d["b"] still 3 (independent)
c["a"].append(3)  # d["a"] also [1, 2, 3] (shared!)

# Deep copy for full independence
c = copy.deepcopy(d)
c["a"].append(4)  # d["a"] still [1, 2, 3]

Try the Interactive Cheat Sheet

We have built a free interactive Python Dictionary Methods Cheat Sheet that puts all 40+ methods at your fingertips. Features include:

  • Real-time search — Type any method name or keyword
  • Category filtering — Access, Update, Remove, Query, Merge, Comprehensions, Patterns
  • Syntax highlighting — Color-coded Python code
  • One-click copy — Copy any code example instantly
  • Mutates vs Returns New badges — Know which methods modify the original
  • Comparison tables — d[key] vs get() vs setdefault(), merge methods
  • Pro tips section — Common pitfalls and advanced techniques

Interactive Tool:

Python Dictionary Methods Cheat Sheet — Interactive Reference

The Gardener's Greenhouse aesthetic. 100% client-side. No signup required.

Summary

Python dictionaries are the backbone of Python programming. Mastering their methods and patterns makes you write cleaner, more efficient code:

  • Use d[key] when the key must exist; use d.get() for safe access with defaults
  • Use setdefault() for lazy initialization; prefer defaultdict for automatic factory defaults
  • Merge with | for new dicts (3.9+), {**a, **b} for older Python, update() or |= for in-place
  • Use pop() when you need the removed value; use del when you don't; use popitem() for LIFO stack behavior
  • Remember that keys(), values(), and items() return dynamic views, not copies
  • Dictionary comprehensions are faster and more readable than equivalent for-loops
  • Use Counter for frequency counting, defaultdict(list) for grouping
  • Never modify a dictionary while iterating over it directly
  • Never use mutable default arguments
  • Use copy.deepcopy() when you need true independence from nested mutable objects

Bookmark the interactive cheat sheet and the DevToolkit homepage for quick access to all 70+ developer tools.


Related Resources

Found this useful? Check out our free developer tools or browse more articles.