Search code examples
pythonpython-2.7classdictionarydeep-copy

Why the results of a deep copy of a dictionary, containing instances, is different from a deep copy of another dictionary, which contains lists?


When debugging my homework, I realised that I needed to use deepcopy to copy a dictionary.

I expected deepcopy to give me results like (which is true when dealing with a dictionary with lists):

import copy

dict3 = {1 : [1,2,3], 2 : [1,2]}    
dict4 = copy.deepcopy(dict3)        

print dict3                         # {1: [1, 2, 3], 2: [1, 2]}
print dict4                         # {1: [1, 2, 3], 2: [1, 2]}

print dict3 == dict4                # True

However, I found something like:

import copy

class Fruit(object):
    def __init__(self, name, color):
        self.name = name
        self.color = color

    def __repr__(self):
        return self.color

# Building dict1
dict1 = {}
dict1['apple'] = Fruit('apple', 'red')
dict1['banana'] = Fruit('banana', 'yellow')

# Deep copy dict1 and assign it to dict2
dict2 = copy.deepcopy(dict1)

print dict1           # {'apple': red, 'banana': yellow}
print dict2           # {'apple': red, 'banana': yellow}

print dict1 == dict2  # False

If I want a copy that gives me a True in the last print statement, what should I do?


Solution

  • The issue is that in python, by default, a copy of an object does not compare equal to the original even if they are the "same", for example:

    class Fruit(object):
        def __init__(self, name, color):
            self.name = name
            self.color = color
    
        def __repr__(self):
            return self.color
    
    print Fruit("apple", "red") == Fruit("apple", "red")
    # False
    

    To fix this, you need to tell python how objects of type Fruit should be compared, for example:

    class Fruit(object):
        def __init__(self, name, color):
            self.name = name
            self.color = color
    
        def __repr__(self):
            return self.color
    
        def __eq__(self, other):
            try:
                if (self.name == other.name) and (self.color == other.color):
                    return True
                else:
                    return False
            except AttributeError:
                return False