6

In Python, if I copy a list or a dictionary, the copied instance is equal to the original:

>>> a = [1, 2, 3]
>>> b = copy.copy(a)
>>> a == b
True
>>> a = {"a":1, "b":2}
>>> b = copy.copy(a)
>>> a == b
True

But if I copy an object, the result is not equal to the original:

>>> class MyClass():
...     def __init__(self, name):
...             self._name= name
...
>>> a = MyClass('a')
>>> b = copy.copy(a)
>>> a == b
False

Why?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
NeoWang
  • 17,361
  • 24
  • 78
  • 126
  • Related: *[How to clone or copy a list in Python?](http://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list-in-python?lq=1)* (not a duplicate, but perhaps it exists somewhere?). – Peter Mortensen Jul 23 '15 at 11:01

1 Answers1

6

Equality in Python for objects is checked by calling the __eq__() function.

Example:

>>> class CA:
...     def __eq__(self, other):
...             print("Equals")
...             return True
...
>>> c = CA()
>>> b = CA()
>>> c == b
Equals
True

That is because list equality is dependent on the elements and not the actual memory location (reference) where the list is stored, that is, they can be two different list references, but if they have the same elements in the same order, the lists are equal.

Example:

>>> l = [1,2]
>>> l1 = [1,2]
>>> id(l)
2830504
>>> id(l1)
2831864
>>> l == l1
True

But custom class, you have not overwritten __eq__(), hence it would call the __eq__() of the parent class, which is object, and that checks equality based on the reference.

And when you do copy.copy() it does shallow copying, that is, it creates a new instance the object with all its members (attributes, etc.) remaining the same. Hence, they are unequal (as they are different references/different instances).

If you want your MyClass to check equality based on self._name, you will have to overwrite the __eq__() function for that.

You can find more information about comparisons here.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
  • 1
    I think this is not the answer to this question at all, since OP's question is about copying the classes and instances not `==` operation! – Mazdak Jul 11 '15 at 06:17
  • 1
    His question is - `list instances created using copy.copy are equal` - but custom classes are not, thats what i have answered, and the OP has accepted it, if you think you have a better answer go at it – Anand S Kumar Jul 11 '15 at 06:19
  • @Kasra And I have explained in the answer - `when you do copy.copy() it does shallow copying, that is the new object is a new reference` - and the reason for `not equality` is not having the `__eq__()` , function. Can you explain how this is not the answer? – Anand S Kumar Jul 11 '15 at 06:25
  • I would add to @AnandSKumar's answer the definition of what `copy.copy()` does for lists, dictionaries and custom classes: for all of them, it creates a new instance of the object, with exactly the same properties (like the elements in the list, or the name in `MyClass`), but in a new reference. Then it all depends on the `__eq__` function. – tomasyany Jul 11 '15 at 06:39