Mathew K Analytics

Lesson 8 · Python data types deep dive

Python Dictionaries Explained: Keys, Methods & Nesting | Data Types #8

Video eight of the twelve-part series: dict, Python's key-value mapping type and one of the most-used data structures in the entire language. Construction,…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Python Data Types Deep-Dive, Video 8: Dictionaries (dict)#

  • Video eight of the twelve-part series: dict, Python's key-value mapping type and one of the most-used data structures in the entire language.
  • Construction, access, all eleven public dict methods, views, comprehensions, and merging.
  • Let's get into it.

Part 1: What Makes dict Different#

person = {'name': 'Ana', 'age': 29, 'city': 'Lima'}
print(type(person))
print(len(person))
print(person['name'])
person['age'] = 30
print(person)
<class 'dict'>
3
Ana
{'name': 'Ana', 'age': 30, 'city': 'Lima'}

Part 2: Dict Literals and Construction#

empty = {}
also_empty = dict()
from_kwargs = dict(name='Sam', age=25)
from_pairs = dict([('a', 1), ('b', 2)])
keys = ['x', 'y', 'z']
values = [10, 20, 30]
from_zip = dict(zip(keys, values))
print(empty, also_empty, from_kwargs, from_pairs, from_zip)
{} {} {'name': 'Sam', 'age': 25} {'a': 1, 'b': 2} {'x': 10, 'y': 20, 'z': 30}
defaults = dict.fromkeys(['a', 'b', 'c'], 0)
print(defaults)
no_default = dict.fromkeys(['x', 'y', 'z'])
print(no_default)
{'a': 0, 'b': 0, 'c': 0}
{'x': None, 'y': None, 'z': None}

Part 3: Accessing Values: indexing and get()#

person = {'name': 'Ana', 'age': 29}
print(person['name'])
try:
    print(person['email'])
except KeyError as e:
    print(f'Caught: {e}')
print(person.get('email'))
print(person.get('email', 'not provided'))
print(person.get('name', 'not provided'))
Ana
Caught: 'email'
None
not provided
Ana

Part 4: Adding and Updating: assignment, update(), setdefault()#

person = {'name': 'Ana'}
person['age'] = 29
print(person)
person.update({'age': 30, 'city': 'Lima'})
print(person)
person.update(country='Peru', age=31)
print(person)
{'name': 'Ana', 'age': 29}
{'name': 'Ana', 'age': 30, 'city': 'Lima'}
{'name': 'Ana', 'age': 31, 'city': 'Lima', 'country': 'Peru'}
counts = {'apple': 3}
result = counts.setdefault('apple', 0)
print(result, counts)
result = counts.setdefault('banana', 0)
print(result, counts)
counts.setdefault('banana', 0)
counts['banana'] += 1
print(counts)
3 {'apple': 3}
0 {'apple': 3, 'banana': 0}
{'apple': 3, 'banana': 1}

Part 5: Removing: pop(), popitem(), clear()#

person = {'name': 'Ana', 'age': 29, 'city': 'Lima'}
age = person.pop('age')
print(age, person)
missing = person.pop('email', 'no email on file')
print(missing)
try:
    person.pop('email')
except KeyError as e:
    print(f'Caught: {e}')
29 {'name': 'Ana', 'city': 'Lima'}
no email on file
Caught: 'email'
stack_dict = {'a': 1, 'b': 2, 'c': 3}
last_pair = stack_dict.popitem()
print(last_pair, stack_dict)
stack_dict.clear()
print(stack_dict)
('c', 3) {'a': 1, 'b': 2}
{}

Part 6: Views: keys(), values(), items()#

scores = {'Ana': 85, 'Sam': 92, 'Lee': 78}
print(scores.keys())
print(scores.values())
print(scores.items())
for key in scores.keys():
    print(key)
for key in scores:
    print(key)
dict_keys(['Ana', 'Sam', 'Lee'])
dict_values([85, 92, 78])
dict_items([('Ana', 85), ('Sam', 92), ('Lee', 78)])
Ana
Sam
Lee
Ana
Sam
Lee
scores = {'Ana': 85, 'Sam': 92, 'Lee': 78}
for name, score in scores.items():
    print(f'{name}: {score}')
view = scores.keys()
scores['Lee'] = 100
print(view)
Ana: 85
Sam: 92
Lee: 78
dict_keys(['Ana', 'Sam', 'Lee'])

Part 7: copy() and Copy Semantics#

original = {'a': 1, 'b': 2}
alias = original
alias['c'] = 3
print(original)
print(original is alias)
real_copy = original.copy()
real_copy['d'] = 4
print(original)
print(real_copy)
{'a': 1, 'b': 2, 'c': 3}
True
{'a': 1, 'b': 2, 'c': 3}
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
nested = {'user': {'name': 'Ana', 'tags': ['admin']}}
shallow = nested.copy()
shallow['user']['tags'].append('verified')
print(nested)
import copy as copy_module
deep = copy_module.deepcopy(nested)
deep['user']['tags'].append('new')
print(nested)
print(deep)
{'user': {'name': 'Ana', 'tags': ['admin', 'verified']}}
{'user': {'name': 'Ana', 'tags': ['admin', 'verified']}}
{'user': {'name': 'Ana', 'tags': ['admin', 'verified', 'new']}}

Part 8: Dict Comprehensions#

squares = {n: n ** 2 for n in range(6)}
print(squares)
words = ['apple', 'kiwi', 'banana']
lengths = {w: len(w) for w in words}
print(lengths)
scores = {'Ana': 85, 'Sam': 45, 'Lee': 92}
passing = {name: score for name, score in scores.items() if score >= 60}
print(passing)
swapped = {value: key for key, value in scores.items()}
print(swapped)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
{'apple': 5, 'kiwi': 4, 'banana': 6}
{'Ana': 85, 'Lee': 92}
{85: 'Ana', 45: 'Sam', 92: 'Lee'}

Part 9: Merging Dictionaries#

defaults = {'theme': 'light', 'font_size': 12}
overrides = {'font_size': 16, 'language': 'en'}
merged = defaults | overrides
print(merged)
print(defaults)
defaults |= overrides
print(defaults)
{'theme': 'light', 'font_size': 16, 'language': 'en'}
{'theme': 'light', 'font_size': 12}
{'theme': 'light', 'font_size': 16, 'language': 'en'}

Part 10: Nested Dictionaries#

company = {
    'name': 'Acme',
    'employees': {
        'Ana': {'role': 'engineer', 'salary': 95000},
        'Sam': {'role': 'designer', 'salary': 85000}
    }
}
print(company['employees']['Ana']['role'])
for emp_name, details in company['employees'].items():
    print(f"{emp_name}: {details['role']}")
engineer
Ana: engineer
Sam: designer

Part 11: Common Patterns and Pitfalls#

valid = {(1, 2): 'point', 'name': 'value', 42: 'answer'}
print(valid)
try:
    invalid = {['a', 'b']: 'value'}
except TypeError as e:
    print(f'Caught: {e}')
{(1, 2): 'point', 'name': 'value', 42: 'answer'}
Caught: unhashable type: 'list'
def broken_tally(item, counts={}):
    counts[item] = counts.get(item, 0) + 1
    return counts
print(broken_tally('a'))
print(broken_tally('a'))
print(broken_tally('b'))
def fixed_tally(item, counts=None):
    if counts is None:
        counts = {}
    counts[item] = counts.get(item, 0) + 1
    return counts
print(fixed_tally('a'))
print(fixed_tally('a'))
{'a': 1}
{'a': 2}
{'a': 2, 'b': 1}
{'a': 1}
{'a': 1}

Wrap-Up: What You Learned#

  • dict maps keys to values, is mutable, and preserves insertion order.
  • Construction: literals, dict(), fromkeys, from pairs, and from zipped sequences.
  • Access: square brackets versus the safer get().
  • Adding and updating: assignment, update(), setdefault().
  • Removing: pop(), popitem(), clear().
  • Views: keys(), values(), items(), and their live, auto-syncing behavior.
  • Copy semantics, dict comprehensions, merging with the pipe operator, and nested dictionaries.
  • Hashable-key requirements and the mutable-default-argument pitfall.
  • That's all eleven public dict methods covered. Next up: set, for unique, unordered collections.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.