7.2. Core Operations#

Hide code cell source

import sys
from pathlib import Path

# Find project root by looking for _config.yml
current = Path.cwd()
for parent in [current, *current.parents]:
    if (parent / '_config.yml').exists():
        project_root = parent
        break
else:
    project_root = Path.cwd().parent.parent

# Add project root to path
sys.path.insert(0, str(project_root))

# Import shared teaching helpers and cell magics
from shared import thinkpython, diagram, jupyturtle, structshape
from shared.download import download

Common dictionary operations involve the following methods.

Group

Method

Description

Reading

d.get(key, default)

Get value safely, no KeyError

d.keys()

All keys

d.values()

All values

d.items()

All key-value pairs

Adding/Updating

d.update({...})

Add or overwrite from another dict

d.setdefault(key, default)

Set value only if key doesn’t exist

Removing

d.pop(key, default)

Remove & return a specific key

d.popitem()

Remove & return last inserted pair

d.clear()

Remove everything

Copying/Creating

d.copy()

Shallow copy

dict.fromkeys(keys, value)

Create new dict from a list of keys

Checking

'key' in d

Check if key exists

len(d)

Count of key-value pairs

Lists identify elements by their positions; dictionaries identify values by their keys. The following table compares the core operations for both types.

Operation

List nums

Dictionary d

Read one value

nums[i] uses an integer index.

d[key] uses a key.

Read with a fallback

No equivalent to dictionary get().

d.get(key, default) returns the default if the key is missing.

Replace one value

nums[i] = value requires an existing index.

d[key] = value replaces an existing value or adds a new entry.

Add an item

nums.append(value) adds to the end; nums.insert(i, value) adds at a position.

d[key] = value adds an entry if the key is new.

Delete without returning a value

del nums[i] removes an element; del nums[i:j] removes a slice.

del d[key] removes an entry.

Remove by value

nums.remove(value) removes the first matching element and returns None; it raises ValueError if no match exists.

No remove() method; delete an entry by its key using del or pop().

Remove and return one value

nums.pop(i) removes by index; no default-value argument is available.

d.pop(key, default) removes by key; the optional default handles a missing key.

Remove the last item

nums.pop() returns the last element.

d.popitem() returns the last inserted (key, value) pair.

Remove everything

nums.clear()

d.clear()

Test membership

value in nums checks elements.

key in d checks keys; value in d.values() checks values.

Iterate

for value in nums yields elements.

for key in d yields keys; for key, value in d.items() yields pairs.

Count items

len(nums) counts elements.

len(d) counts key-value pairs.

For an invalid lookup or removal without a fallback, a list raises IndexError for an out-of-range index, while a dictionary raises KeyError for a missing key.

7.2.1. Accessing Items#

Common ways to access values in a dictionary include:

  • dict[key]

  • dict.get(key)

  • dict.get(key, default)

We use square brackets [] to access and modify items in a Python dictionary by key. Reading a value looks like dict[key], which returns the value stored under key.

If a key you a key you try to access is missing, you will receive an error. To avoid the error, use dict.get(key), which returns None or a default value you provide when error.

person = {
    "name": "Alice",
    "age": 28,
    "city": "Rolla"
}

# Access an item
print(person["name"])      # Alice
print(person)
Alice
{'name': 'Alice', 'age': 28, 'city': 'Rolla'}

KeyError when trying to access a nonexistent key.

%%expect KeyError
print(person["phone"])      # KeyError
KeyError: 'phone'

When accessing, it is safer to use dict.get() to avoid the error because it

  • returns None when the key does not exist

  • returns a default value you specify when the key does not exist

print(person.get("phone"))          # None
print(person.get("phone", "N/A"))   # N/A
None
N/A
numbers = {'zero': 0, 'one': 1, 'two': 2}

To access all the keys and values at once:

  • keys() returns a view of all the dictionary’s keys

  • values() returns a view of all the dictionary’s values.

  • items() returns a view of all key-value pairs as tuples.

for k in numbers.keys():
    print(k, end=' ')
print()

for v in numbers.values():
    print(v, end=' ')
print()

for k, v in numbers.items():
    print(k, v , end=' ')
zero one two 
0 1 2 
zero 0 one 1 two 2 

The len function works on dictionaries; it returns the number of items.

len(numbers)
3
### Exercise: Accessing Dictionary Values
# Given the dictionary below:
person = {"name": "Bob", "age": 25, "city": "Chicago"}

# 1. Print the value associated with "name".
# 2. Use .get() to retrieve "email" with a default of "N/A".
# 3. Print all keys and values using .items().
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
person = {"name": "Bob", "age": 25, "city": "Chicago"}

# 1. Access "name"
print(person["name"])

# 2. Get "email" safely with a default
print(person.get("email", "N/A"))

# 3. Iterate with .items()
for key, value in person.items():
    print(key, value)
Bob
N/A
name Bob
age 25
city Chicago

7.2.2. Adding/Updating Items#

You also use the square brackets to update values. An item assignment like person["age"] = 30 will either

  • updates an existing item, or

  • creates a new item if the key does not already exist.

Note that, since dictionary keys are immutable, you can not modify it directly.

# Modify an existing item
person["age"] = 29

# Add a new item
person["email"] = "alice@rolla.com"

print(person)
{'name': 'Bob', 'age': 29, 'city': 'Chicago', 'email': 'alice@rolla.com'}

d.update() is used to add new key-value pairs or change existing ones in a dictionary. d.update() behaves like above but can work with multiple key-value pairs:

  • if the key already exists, its value is replaced

  • if the key does not exist, it is added

d = {"a": 1, "b": 2}
d.update({"b": 20, "c": 3})

print(d)   # {'a': 1, 'b': 20, 'c': 3}
{'a': 1, 'b': 20, 'c': 3}

An alternative syntax for d.update() is as follows.

d.update(a=10, d=4)
print(d)   # {'a': 10, 'b': 20, 'c': 3, 'd': 4}
{'a': 10, 'b': 20, 'c': 3, 'd': 4}

You cannot rename or update a key in place because dictionary keys are immutable. Instead, you could:

  1. Add a new key

  2. Copy the value

  3. Delete the old key

You can do all three steps in one line of code, because pop() will return the value that’s been removed, as shown below. I think that’s pretty neat.

student = {
    "name": "Doris",
    "age": 29
}

# Rename key "age" to "years"
student["years"] = student.pop("age")

print(student)
{'name': 'Doris', 'years': 29}
### Exercise: Adding and Updating Dictionary Items
# Start with this dictionary:
person = {"name": "Alice", "age": 28}

# 1. Add a new key "email" with value "alice@example.com".
# 2. Update "age" to 30.
# 3. Use d.update() to add "city": "Boston" and change "name" to "Alicia".
# 4. Print the final dictionary.
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
person = {"name": "Alice", "age": 28}

# 1. Add "email"
person["email"] = "alice@example.com"

# 2. Update "age"
person["age"] = 30

# 3. Use update()
person.update({"city": "Boston", "name": "Alicia"})

# 4. Print
print(person)
{'name': 'Alicia', 'age': 30, 'email': 'alice@example.com', 'city': 'Boston'}

7.2.3. Deleting Items#

You can remove a key-value pair when you no longer need it:

  • del d[key] removes the item with the given key.

  • d.pop(key) removes the item with the given key and returns its value.

  • d.popitem() removes the last inserted item and returns it as a (key, value) tuple.

  • d.clear() removes all items.

del is a Python keyword used in a statement, rather than a method call. It deletes the target you specify: del d[key] removes a dictionary entry, del nums[0] removes a list element, and del nums[1:3] removes a list slice. You can also use del name to remove a variable binding; this does not necessarily destroy the object, because other variables may still refer to it. Unlike pop(), del does not return the removed value.

Both del d[key] and d.pop(key) raise KeyError if the key is missing. To handle a missing key without an error, use d.pop(key, default). It returns the default value and leaves the dictionary unchanged; it does not insert the default.

Unlike dictionary pop(), which requires a key, list pop(index) takes an optional index and has no default-value argument. List pop() with no argument is closer to dictionary popitem(): both remove the last item, but the list returns an element and the dictionary returns a key-value pair.

person = {
    "name": "Alice",
    "age": 29,
    "city": "Rolla",
    "email": "alice@rolla.com"
}
print("person:\t\t", person)

# Delete an item using del
del person["city"]                          # in place
print("city deleted:\t", person)

# Delete an item using pop()
email_popped = person.pop("email")

print("x_city_email:\t", person)            # {'name': 'Alice', 'age': 29}
print("email_popped:\t", email_popped)      # alice@rolla.com

print("person_updated\t", person)

# Delete the last added item using popitem() 
key, value = person.popitem()
print("popped_k_v:\t", (key, value))        # ('age', 29) 
print("after_popitem:\t", person)           # {'name': 'Alice'}

# Clear all items from the dictionary
person.clear()
print("after_clear:\t", person)  # {}
person:		 {'name': 'Alice', 'age': 29, 'city': 'Rolla', 'email': 'alice@rolla.com'}
city deleted:	 {'name': 'Alice', 'age': 29, 'email': 'alice@rolla.com'}
x_city_email:	 {'name': 'Alice', 'age': 29}
email_popped:	 alice@rolla.com
person_updated	 {'name': 'Alice', 'age': 29}
popped_k_v:	 ('age', 29)
after_popitem:	 {'name': 'Alice'}
after_clear:	 {}
person = {"name": "Alice", "city": "Rolla"}

print(person.pop("city", "N/A"))   # Rolla: the key exists
print(person.pop("phone", "N/A"))  # N/A: the key is missing
print(person)                      # {'name': 'Alice'}
Rolla
N/A
{'name': 'Alice'}
### Exercise: Deleting Dictionary Items
# Start with this dictionary:
person = {"name": "Bob", "age": 25, "city": "Boston", "email": "bob@email.com"}

# 1. Delete "city" using del.
# 2. Remove and capture "email" using pop(). Print the popped value.
# 3. Print the remaining dictionary.
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
person = {"name": "Bob", "age": 25, "city": "Boston", "email": "bob@email.com"}

# 1. Delete "city"
del person["city"]

# 2. Pop "email"
email_val = person.pop("email")
print("Popped email:", email_val)

# 3. Print remaining
print(person)
Popped email: bob@email.com
{'name': 'Bob', 'age': 25}

7.2.4. Membership Testing#

The in membership operator works on dictionaries, too; it tells you whether a key exists in the dictionary, which returns True if the key is present and False if it is not. You can also use not in to check that a key is missing.

Member testing is useful when you want to safely decide whether to access, update, or delete a dictionary item.

person = {
    "name": "Alice",
    "age": 29,
    "city": "Rolla"
}

print("name" in person)        # True
print("email" in person)       # False
print("email" not in person)   # True

if "age" in person:             # safety: Check if key exists before accessing
    print("Age exists:", person["age"])
True
False
True
Age exists: 29

The in operator does not check whether something appears as a value.

"Alice" in person
False

To see whether something appears as a value in a dictionary, you can use the method values, which returns a sequence of values, and then use the in operator.

"Alice" in person.values()
True
### Exercise: Membership Testing
# Use the dictionary below:
person = {"name": "Alice", "age": 29, "city": "Rolla"}

# 1. Check if "name" is in the dictionary and print the result.
# 2. Check if "phone" is NOT in the dictionary and print the result.
# 3. Check if "Alice" appears as a value and print the result.
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
person = {"name": "Alice", "age": 29, "city": "Rolla"}

# 1. "name" in person
print("name" in person)              # True

# 2. "phone" not in person
print("phone" not in person)         # True

# 3. "Alice" in values
print("Alice" in person.values())    # True
True
True
True