These are related to copying mutable objects. I assume you know the difference between copying by value and copying by reference. Let ‘a’ be a mutable object of some type.
b = a copies ‘a’ by reference, so ‘b’ and ‘a’ refer to the same object. Therefore b.field1 = 2 makes a.field1 == 2 true.
b = copy(a) makes a new object of the same type as the object which ‘a’ refers to, and makes ‘b’ refer to it. So there are now 2 different objects, one for ‘a’ and one for ‘b’. Then for each ‘field’ of the new object, b.field = a.field is called. Therefore, if the field type is immutable it will be copied by value. If it is mutable, it will be copied by reference. Notice that this is a shallow copy, as b.field1.field11 = 2 still makes a.field1.field11 == 2 true, where field1 is a mutable object of some type.
b = deepcopy(a) keeps unwrapping any mutables inside of ‘a’ until it reaches all the immutables at all the levels, and copies all the data and structure of the old object to a new object. So ‘b’ and ‘a’ become completely independent, and changing one at any level does not change the other. For example b.field1.field11.field111 = 2 does not change a.field1.field11.field111. This however comes at the cost of using more memory when dealing with deep structures, e.g. a root node in a deep tree.