oop - How can I create a copy of an object in Python? - Stack Overflow
Use case of the .copy() method
python when to use copy.copy - Stack Overflow
Why is copying a list so damn difficult in python?
To get a fully independent copy of an object you can use the copy.deepcopy() function.
For more details about shallow and deep copying please refer to the other answers to this question and the nice explanation in this answer to a related question.
How can I create a copy of an object in Python?
So, if I change values of the fields of the new object, the old object should not be affected by that.
You mean a mutable object then.
In Python 3, lists get a copy method (in 2, you'd use a slice to make a copy):
>>> a_list = list('abc')
>>> a_copy_of_a_list = a_list.copy()
>>> a_copy_of_a_list is a_list
False
>>> a_copy_of_a_list == a_list
True
Shallow Copies
Shallow copies are just copies of the outermost container.
list.copy is a shallow copy:
>>> list_of_dict_of_set = [{'foo': set('abc')}]
>>> lodos_copy = list_of_dict_of_set.copy()
>>> lodos_copy[0]['foo'].pop()
'c'
>>> lodos_copy
[{'foo': {'b', 'a'}}]
>>> list_of_dict_of_set
[{'foo': {'b', 'a'}}]
You don't get a copy of the interior objects. They're the same object - so when they're mutated, the change shows up in both containers.
Deep copies
Deep copies are recursive copies of each interior object.
>>> lodos_deep_copy = copy.deepcopy(list_of_dict_of_set)
>>> lodos_deep_copy[0]['foo'].add('c')
>>> lodos_deep_copy
[{'foo': {'c', 'b', 'a'}}]
>>> list_of_dict_of_set
[{'foo': {'b', 'a'}}]
Changes are not reflected in the original, only in the copy.
Immutable objects
Immutable objects do not usually need to be copied. In fact, if you try to, Python will just give you the original object:
>>> a_tuple = tuple('abc')
>>> tuple_copy_attempt = a_tuple.copy()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'copy'
Tuples don't even have a copy method, so let's try it with a slice:
>>> tuple_copy_attempt = a_tuple[:]
But we see it's the same object:
>>> tuple_copy_attempt is a_tuple
True
Similarly for strings:
>>> s = 'abc'
>>> s0 = s[:]
>>> s == s0
True
>>> s is s0
True
and for frozensets, even though they have a copy method:
>>> a_frozenset = frozenset('abc')
>>> frozenset_copy_attempt = a_frozenset.copy()
>>> frozenset_copy_attempt is a_frozenset
True
When to copy immutable objects
Immutable objects should be copied if you need a mutable interior object copied.
>>> tuple_of_list = [],
>>> copy_of_tuple_of_list = tuple_of_list[:]
>>> copy_of_tuple_of_list[0].append('a')
>>> copy_of_tuple_of_list
(['a'],)
>>> tuple_of_list
(['a'],)
>>> deepcopy_of_tuple_of_list = copy.deepcopy(tuple_of_list)
>>> deepcopy_of_tuple_of_list[0].append('b')
>>> deepcopy_of_tuple_of_list
(['a', 'b'],)
>>> tuple_of_list
(['a'],)
As we can see, when the interior object of the copy is mutated, the original does not change.
Custom Objects
Custom objects usually store data in a __dict__ attribute or in __slots__ (a tuple-like memory structure.)
To make a copyable object, define __copy__ (for shallow copies) and/or __deepcopy__ (for deep copies).
from copy import copy, deepcopy
class Copyable:
__slots__ = 'a', '__dict__'
def __init__(self, a, b):
self.a, self.b = a, b
def __copy__(self):
return type(self)(self.a, self.b)
def __deepcopy__(self, memo): # memo is a dict of id's to copies
id_self = id(self) # memoization avoids unnecesary recursion
_copy = memo.get(id_self)
if _copy is None:
_copy = type(self)(
deepcopy(self.a, memo),
deepcopy(self.b, memo))
memo[id_self] = _copy
return _copy
Note that deepcopy keeps a memoization dictionary of id(original) (or identity numbers) to copies. To enjoy good behavior with recursive data structures, make sure you haven't already made a copy, and if you have, return that.
So let's make an object:
>>> c1 = Copyable(1, [2])
And copy makes a shallow copy:
>>> c2 = copy(c1)
>>> c1 is c2
False
>>> c2.b.append(3)
>>> c1.b
[2, 3]
And deepcopy now makes a deep copy:
>>> c3 = deepcopy(c1)
>>> c3.b.append(4)
>>> c1.b
[2, 3]
I am trying to understand how shallow copies are useful, if any operation I perform on them will still be applied to the original list. When will I ever need to use them?
Basically, b = a points b to wherever a points, and nothing else.
What you're asking about is mutable types. Numbers, strings, tuples, frozensets, booleans, None, are immutable. Lists, dictionaries, sets, bytearrays, are mutable.
If I make a mutable type, like a list:
>>> a = [1, 2] # create an object in memory that points to 1 and 2, and point a at it
>>> b = a # point b to wherever a points
>>> a[0] = 2 # change the object that a points to by pointing its first item at 2
>>> a
[2, 2]
>>> b
[2, 2]
They'll both still point to the same item.
I'll comment on your original code too:
>>>a=5 # '5' is interned, so it already exists, point a at it in memory
>>>b=a # point b to wherever a points
>>>a=6 # '6' already exists in memory, point a at it
>>>print b # b still points at 5 because you never moved it
5
You can always see where something points to in memory by doing id(something).
>>> id(5)
77519368
>>> a = 5
>>> id(a)
77519368 # the same as what id(5) showed us, 5 is interned
>>> b = a
>>> id(b)
77519368 # same again
>>> id(6)
77519356
>>> a = 6
>>> id(a)
77519356 # same as what id(6) showed us, 6 is interned
>>> id(b)
77519368 # still pointing at 5.
>>> b
5
You use copy when you want to make a copy of a structure. However, it still will not make a copy of something that is interned. This includes integers less than 256, True, False, None, short strings like a. Basically, you should almost never use it unless you're sure you won't be messed up by interning.
Consider one more example, that shows even with mutable types, pointing one variable at something new still doesn't change the old variable:
>>> a = [1, 2]
>>> b = a
>>> a = a[:1] # copy the list a points to, starting with item 2, and point a at it
>>> b # b still points to the original list
[1, 2]
>>> a
[1]
>>> id(b)
79367984
>>> id(a)
80533904
Slicing a list (whenever you use a :) makes a copy.
Assignment never copies. It just links the object the a references (to stick to the example) to b. a and b reference the same object until you change the link of one.
It's useful to drop "variable" as a term, it's just a label you put on an object, a handle you can use to get through to the object, nothing more.
copy.copy doesn't change this at all.
If you want to propagate changes even for numbers or strings - here does the immutability show - you have to wrap the numbers and strings in a another object and assign it to a and b.
If you want to go the other way round you have to use the copy module, but make sure to read the docs. But you have to think in term of objects not variables.