Python Dictionary Storage of Custom Objects: The Importance of References vs. Deep Copies

In Python programming, a dictionary is a very powerful data structure that allows us to associate key-value pairs and efficiently search and manipulate these data. When we try to store custom objects in a dictionary, we often encounter a crucial concept: In Python, object assignment is actually reference assignment, not a deep copy of the object itself. This means that when you put a custom object into a dictionary, the dictionary stores a reference to that object, rather than a brand new copy of the object.

Basic Example of Storing Custom Objects

Let’s consider a simple Person class:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

# Create a Person object
p1 = Person("Alice", 30)

# Store the object in a dictionary
people_dict = {}
people_dict["alice"] = p1

In this example, the people_dict dictionary now contains an item with a key "alice" and its value is a reference to the Person type object p1. If we modify the properties of this object:

p1.age = 31

Then when accessing this object through the dictionary, we will find that its age has also been updated:

print(people_dict["alice"].age)  # Output: 31

This is because the dictionary stores references to Person objects rather than independent copies of them. It stores a reference to the same memory address.

Deep Copy vs. Shallow Copy

This referencing behavior can lead to unexpected results when dealing with nested data structures or custom objects. For example, if a custom object contains mutable attributes (such as lists or another custom object), directly storing such an object in a dictionary and modifying it will affect the object obtained through the dictionary.

class Address:
    def __init__(self, street, city):
        self.street = street
        self.city = city

class Person:
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address

address = Address("Main St.", "Springfield")
p1 = Person("Bob", 40, address)
people_dict["bob"] = p1

# Modify the original address object
address.city = "Shelbyville"

# The person in the dictionary's address also changed
print(people_dict["bob"].address.city)  # Output: Shelbyville

Solution: Deep Copy

To avoid problems caused by shared state, we sometimes need to ensure that the dictionary stores a complete copy of the object, rather than a reference to it. Python provides the copy module’s deepcopy function to achieve this goal:

import copy

# Use deep copy to store objects
people_dict["bob_deepcopy"] = copy.deepcopy(p1)

# Now even if you modify the original address object, the deep copied object is not affected
address.city = "Capital City"
print(people_dict["bob"].address.city)  # Output: Capital City
print(people_dict["bob_deepcopy"].address.city)  # Output: Shelbyville

In summary, when using dictionaries to store custom objects in Python, be sure to pay attention to the fact that they default to storing object references. For situations where you need to maintain independent states, use deepcopy to perform a deep copy to avoid unexpected data changes due to shared referencing.

Licensed under CC BY-NC-SA 4.0
Last updated on Jun 02, 2025 20:54
A financial IT programmer's tinkering and daily life musings
Built with Hugo
Theme Stack designed by Jimmy