A Python dictionary (dict) is a mutable collection of key-value pairs, written in curly braces as {key: value}, where each key is unique and maps to one value. A key lookup takes about the same time in a dictionary of ten items or ten million, and since Python 3.7 a dictionary keeps its items in insertion order.
person = {"name": "Lokesh", "age": 39}
name = person["name"] # 'Lokesh'
person["blog"] = "howtodoinjava" # add a new key
country = person.get("country", "India") # 'India', a default for a missing key
Keys must be hashable, such as strings, numbers and tuples of hashable values, and they are case-sensitive. Values can be any object, including lists and other dictionaries. A Python dictionary corresponds to HashMap and Hashtable in Java.
The topics are creating dictionaries, reading values safely, checking, adding, updating and deleting keys, iterating, merging with |, and every dictionary method with its return value. Outputs come from Python 3.14.
1. Creating the Dictionary
There are three common ways to build a dictionary. A literal in curly braces suits fixed data, the dict() constructor converts pairs and keyword arguments, and a comprehension computes the entries.
1.1. With Curly Braces
Each key is separated from its value by a colon, and the pairs are separated by commas. Empty braces create an empty dictionary.
empty = {}
person = {
"name": "Lokesh",
"age": 39,
"blog": "howtodoinjava"
}
print(person)
{'name': 'Lokesh', 'age': 39, 'blog': 'howtodoinjava'}
The output keeps the insertion order. A duplicate key in the literal keeps only the last value, as in {“a”: 1, “a”: 2}, which gives {‘a’: 2}.
1.2. With dict() Constructor
The built-in dict() accepts another mapping, a list of key-value tuples, or keyword arguments. Keyword arguments become string keys, so they must be valid Python names.
d1 = dict({1: "Python", 2: "Example"}) # {1: 'Python', 2: 'Example'}
d2 = dict([(1, "Python"), (2, "Example")]) # {1: 'Python', 2: 'Example'}
d3 = dict(firstName="Lokesh", lastName="Gupta", age=39)
# {'firstName': 'Lokesh', 'lastName': 'Gupta', 'age': 39}
d4 = dict(zip(["a", "b"], [1, 2])) # {'a': 1, 'b': 2}
1.3. With a Dictionary Comprehension
A comprehension computes keys and values from an iterable in one expression.
squares = {n: n * n for n in range(4)} # {0: 0, 1: 1, 2: 4, 3: 9}
2. Accessing the Values
Square brackets return the value for a key and raise KeyError when the key is missing. The get() method returns None, or a default we pass, instead of raising an error.
person = {"name": "Lokesh", "blog": "howtodoinjava", "age": 39}
name = person["name"] # 'Lokesh'
age = person.get("age") # 39
missing = person.get("country") # None
with_default = person.get("country", "India") # 'India'
>>> person["country"]
KeyError: 'country'
We use square brackets when the key must exist, because the KeyError reveals the bug in our code. We use get() for optional keys. The len() function returns the number of key-value pairs.
pairs = len(person) # 3
2.1. Nested Dictionaries
A value can be another dictionary, which is how JSON data looks after json.loads(). Chained square brackets read the inner values, and chained get() calls with an empty dictionary as the default avoid errors when a level is missing.
user = {"name": "Lokesh", "address": {"city": "Delhi", "zip": "110001"}}
city = user["address"]["city"] # 'Delhi'
country = user.get("address", {}).get("country") # None
user["address"]["city"] = "Noida" # change an inner value
3. Check if a Key Exists in Dictionary
The in operator checks the keys of a dictionary, not the values.
3.1. key in dict
The expression returns True when the key is present.
person = {"name": "Lokesh", "blog": "howtodoinjava", "age": 39}
has_name = "name" in person # True
has_value = "Lokesh" in person # False, values are not checked
in_values = "Lokesh" in person.values() # True
3.2. key not in dict
The not in operator is the negation, and it is common in guard clauses.
if "country" not in person:
print("country is not present")
country is not present
4. Adding and Updating the Values
Assigning to a key adds the pair when the key is new and replaces the value when the key exists. The update() method does the same for many pairs at once.
person = {"name": "Lokesh", "blog": "howtodoinjava", "age": 39}
person["name"] = "Alex" # update
person.update({"name": "Brian"}) # update with update()
person["country"] = "India" # add a new key
person.update(city="Delhi", age=40) # several pairs at once
snapshot = person
# {'name': 'Brian', 'blog': 'howtodoinjava', 'age': 40, 'country': 'India', 'city': 'Delhi'}
An update keeps the original position of an existing key. Only new keys go to the end.
4.1. Merging with | and |=
Since Python 3.9, the | operator returns a new merged dictionary and |= merges into the left one. When both sides have the same key, the right side wins.
defaults = {"theme": "light", "lang": "en"}
user = {"lang": "fr"}
settings = defaults | user # {'theme': 'light', 'lang': 'fr'}
defaults |= {"size": 12} # defaults changed in place
5. Deleting Dictionary Items
Python removes items with del, pop(), popitem() and clear().
5.1. Using del Keyword
The del statement removes a key and raises KeyError if it is missing. Used on the name, it deletes the whole variable.
person = {"name": "Lokesh", "blog": "howtodoinjava", "age": 39}
del person["name"]
remaining = person # {'blog': 'howtodoinjava', 'age': 39}
5.2. Using pop() Method
The pop() method removes a key and returns its value. A second argument is returned when the key is missing, which avoids the KeyError.
person = {"name": "Lokesh", "blog": "howtodoinjava", "age": 39}
removed = person.pop("name") # 'Lokesh'
safe = person.pop("country", None) # None, no error
5.3. Using clear() Method
The clear() method removes all items and returns None. The dictionary object stays and is empty.
person = {"name": "Lokesh", "blog": "howtodoinjava", "age": 39}
person.clear()
after = person # {}
6. Iterating over Dictionary Items
A loop over a dictionary visits its keys in insertion order. The values() and items() methods give the values and the key-value pairs.
6.1. Using for Loop
Each pass of the loop receives a key, and the value is read with square brackets.
person = {"name": "Lokesh", "blog": "howtodoinjava", "age": 39}
for k in person:
print(f"Key: {k}, Value: {person[k]}")
Key: name, Value: Lokesh
Key: blog, Value: howtodoinjava
Key: age, Value: 39
6.2. Iterate all Values using values()
The values() method returns a view of the values, without the keys.
for v in {"name": "Lokesh", "blog": "howtodoinjava"}.values():
print("Value:", v)
Value: Lokesh
Value: howtodoinjava
6.3. Iterate all Key-Value Pairs using items()
The items() method returns (key, value) tuples, and unpacking them in the loop header is the most readable form.
for key, value in {"name": "Lokesh", "blog": "howtodoinjava"}.items():
print(f"Key: {key}, Value: {value}")
Key: name, Value: Lokesh
Key: blog, Value: howtodoinjava
Adding or removing keys while looping over a dictionary raises RuntimeError: dictionary changed size during iteration. We loop over list(d) instead, or build a new dictionary with a comprehension.
stock = {"tea": 0, "milk": 4, "sugar": 0}
for item in list(stock):
if stock[item] == 0:
del stock[item]
left = stock # {'milk': 4}
7. Built-in Dictionary Methods
The methods that read return a value or a view, while the methods that change the dictionary in place return None, except pop(), popitem() and setdefault().
| Method | Description | Return value |
|---|---|---|
| clear() | Removes all items | None |
| copy() | Shallow copy | A new dict |
| dict.fromkeys(keys, value=None) | New dict with the given keys, all set to one value | A new dict |
| get(key, default=None) | Value for key, or default | The value or default |
| items() | Live view of (key, value) pairs | dict_items |
| keys() | Live view of keys | dict_keys |
| values() | Live view of values | dict_values |
| pop(key[, default]) | Removes key | The value, or default; KeyError otherwise |
| popitem() | Removes the last inserted pair | A (key, value) tuple; KeyError if empty |
| setdefault(key, default=None) | Inserts key with default if missing | The existing or inserted value |
| update(other) | Adds or replaces pairs | None |
7.1. keys(), values() and items() are Views
These methods return views, not lists. A view reflects later changes to the dictionary, and list() takes a snapshot.
d = {"name": "Lokesh", "blog": "howtodoinjava"}
keys = d.keys()
d["age"] = 39
live = list(keys) # ['name', 'blog', 'age']
items_view = d.items() # dict_items([('name', 'Lokesh'), ('blog', 'howtodoinjava'), ('age', 39)])
7.2. setdefault()
The method returns the value of a key, and inserts the key with the default when it is missing. It is useful for grouping values into lists.
d = {"name": "Lokesh", "blog": "howtodoinjava"}
age = d.setdefault("age", 39) # 39, inserted
name = d.setdefault("name", "Alex") # 'Lokesh', unchanged
groups = {}
for word in ["tea", "toast", "milk"]:
groups.setdefault(word[0], []).append(word)
by_letter = groups # {'t': ['tea', 'toast'], 'm': ['milk']}
7.3. popitem()
The method removes and returns the last inserted pair, so a dictionary works as a LIFO stack of pairs. Before Python 3.7, it removed an arbitrary pair.
d = {"name": "Lokesh", "blog": "howtodoinjava"}
last = d.popitem() # ('blog', 'howtodoinjava')
7.4. fromkeys() and copy()
The fromkeys() class method gives every key the same value object, so a mutable value such as a list is shared. The copy() method is shallow, and nested objects stay shared too.
counts = dict.fromkeys(("key1", "key2", "key3"), 0) # {'key1': 0, 'key2': 0, 'key3': 0}
shared = dict.fromkeys(["a", "b"], [])
shared["a"].append(1) # shared is {'a': [1], 'b': [1]}
separate = {k: [] for k in ["a", "b"]} # one list per key
8. Real-World Example: Counting and Grouping
Dictionaries are the standard tool for counting items and grouping records by a field. The get() method with a default handles the first occurrence, and collections.Counter and defaultdict make the code shorter.
from collections import Counter, defaultdict
words = "the cat and the hat and the bat".split()
counts = {}
for w in words:
counts[w] = counts.get(w, 0) + 1
# counts is {'the': 3, 'cat': 1, 'and': 2, 'hat': 1, 'bat': 1}
top = Counter(words).most_common(2) # [('the', 3), ('and', 2)]
orders = [("alice", 30), ("bob", 15), ("alice", 20)]
by_customer = defaultdict(list)
for customer, amount in orders:
by_customer[customer].append(amount)
totals = {c: sum(a) for c, a in by_customer.items()} # {'alice': 50, 'bob': 15}
When one key needs several values and the order of all pairs matters, as with HTTP headers, the Python MultiDict type is the better fit.
9. Python Dictionary FAQs
The most frequent questions cover ordering, sorting and the rules for keys.
9.1. Are Python dictionaries ordered?
Yes. Since Python 3.7, the language guarantees that a dictionary keeps insertion order. Older tutorials that call dictionaries unordered describe Python 3.5 and earlier. For move-to-end operations, OrderedDict still helps.
9.2. How do we sort a dictionary by value?
The sorted() function with a key on the second item of each pair returns sorted pairs, and dict() rebuilds the dictionary in that order.
scores = {"bob": 72, "alice": 91, "carl": 85}
by_score = dict(sorted(scores.items(), key=lambda kv: kv[1], reverse=True))
# {'alice': 91, 'carl': 85, 'bob': 72}
9.3. Why can a list not be a dictionary key?
Keys must be hashable, and a list can change after it is stored, which would break the lookup. Python 3.14 reports TypeError: cannot use ‘list’ as a dict key (unhashable type: ‘list’). A tuple works as a key when its items are hashable.
10. Conclusion
Dictionaries map unique, hashable keys to values and keep the insertion order. Square brackets read keys that must exist, get() handles optional ones, and | merges two dictionaries. The views from keys(), values() and items() stay in sync with the dictionary, so changing its size inside a loop needs a copy of the keys.
11. References
Happy Learning !!