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.
Answer from Sven Marnach on Stack Overflowoop - How can I create a copy of an object in Python? - Stack Overflow
Should I Use Deepcopy for Class Initializers?
Python - DeepCopy of custom class instance
How to copy a Python class instance if deepcopy() does not work? - Stack Overflow
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]
import copy
class Foo:
def __init__(self, my_list):
self.my_list = copy.deepcopy(my_list)
bar = Foo([0, 1, 2])I always deepcopy objects that isn't deepcopied by default when initializing a function like above. Is this a memory efficient practice, or is it useless?
Yes you can make a copy of class instance using deepcopy:
from copy import deepcopy
c = C(4,5,'r'=2)
d = deepcopy(c)
This creates the copy of class instance 'c' in 'd' .
One way to do that is by implementing __copy__ in the C Class like so:
class A:
def __init__(self):
self.var1 = 1
self.var2 = 2
self.var3 = 3
class C(A):
def __init__(self, a=None, b=None, **kwargs):
super().__init__()
self.a = a
self.b = b
for x, v in kwargs.items():
setattr(self, x, v)
def __copy__(self):
self.normalizeArgs()
return C(self.a, self.b, kwargs=self.kwargs)
# THIS IS AN ADDITIONAL GATE-KEEPING METHOD TO ENSURE
# THAT EVEN WHEN PROPERTIES ARE DELETED, CLONED OBJECTS
# STILL GETS DEFAULT VALUES (NONE, IN THIS CASE)
def normalizeArgs(self):
if not hasattr(self, "a"):
self.a = None
if not hasattr(self, "b"):
self.b = None
if not hasattr(self, "kwargs"):
self.kwargs = {}
cMain = C(a=4, b=5, kwargs={'r':2})
del cMain.b
cClone = cMain.__copy__()
cMain.a = 11
del cClone.b
cClone2 = cClone.__copy__()
print(vars(cMain))
print(vars(cClone))
print(vars(cClone2))

Your first question:
As pointed out by @Blckknght in the comments, when you pass a class-definition object to copy.deepcopy(), you run into a behavior of deepcopy() that is surprising / quirky, though intentional -- instead of making a deep copy of the class-definition object, deepcopy() merely returns a reference to the same class-definition object.
To verify this,
print ("b is:", b)
b_instance = b()
print ("b is Test ?:", (b is Test))
gives:
b is: <class '__main__.Test'>
b is Test ?: True # deepcopy() hasn't made a copy at all !
Here's what the doc says regarding deepcopy() for class-definition objects:
This module does not copy types like module, method, stack trace, stack frame, file, socket, window, array, or any similar types. It does โcopyโ functions and classes (shallow and deeply), by returning the original object unchanged; this is compatible with the way these are treated by the pickle module.
So, when you do
b.a = 1
you're still modifying the class variable of the class Test.
Your second question:
When you do
c = type('Test2', (Test,), {'a': 2})
you are creating a new type called Test2, with its own class variable called a, and having Test as its superclass.
Now Test2.a and Test.a are two different class variables, defined in two different classes, and can take values independently of each other. One is a class variable called a in the superclass Test, the other is a class variable with the same name a in the subclass Test2.
That is why c.a will give 2 (the value to which you initialized it), and Test.a will continue to give 1
You copied the class definition and not the instance itself.
You should be doing something like this instead:
import copy
class Test:
def __init__(self,a):
self.a = a
test1 = Test(0)
test2 = copy.deepcopy(test1)
print("Original:")
print("Test 1: " + str(test1.a)) #0
print("Test 2: " + str(test2.a)) #0
print("Modify test 2 to 10")
test2.a = 10
print("Test 1: " + str(test1.a)) #0
print("Test 2: " + str(test2.a)) #10
Original:
Test 1: 0
Test 2: 0
Modify test 2 to 10
Test 1: 0
Test 2: 10
Putting together Alex Martelli's answer and Rob Young's comment you get the following code:
from copy import copy, deepcopy
class A:
def __init__(self):
print('init')
self.v = 10
self.z = [2, 3, 4]
def __copy__(self):
cls = self.__class__
result = cls.__new__(cls)
result.__dict__.update(self.__dict__)
return result
def __deepcopy__(self, memo):
cls = self.__class__
result = cls.__new__(cls)
memo[id(self)] = result
for k, v in self.__dict__.items():
setattr(result, k, deepcopy(v, memo))
return result
a = A()
a.v = 11
b1, b2 = copy(a), deepcopy(a)
a.v = 12
a.z.append(5)
print(b1.v, b1.z)
print(b2.v, b2.z)
prints
init
11 [2, 3, 4, 5]
11 [2, 3, 4]
here __deepcopy__ fills in the memo dict to avoid excess copying in case the object itself is referenced from its member.
The recommendations for customizing are at the very end of the docs page:
Classes can use the same interfaces to control copying that they use to control pickling. See the description of module pickle for information on these methods. The copy module does not use the copy_reg registration module.
In order for a class to define its own copy implementation, it can define special methods
__copy__()and__deepcopy__(). The former is called to implement the shallow copy operation; no additional arguments are passed. The latter is called to implement the deep copy operation; it is passed one argument, the memo dictionary. If the__deepcopy__()implementation needs to make a deep copy of a component, it should call thedeepcopy()function with the component as first argument and the memo dictionary as second argument.
Since you appear not to care about pickling customization, defining __copy__ and __deepcopy__ definitely seems like the right way to go for you.
Specifically, __copy__ (the shallow copy) is pretty easy in your case...:
def __copy__(self):
newone = type(self)()
newone.__dict__.update(self.__dict__)
return newone
__deepcopy__ would be similar (accepting a memo arg too) but before the return it would have to call self.foo = deepcopy(self.foo, memo) for any attribute self.foo that needs deep copying (essentially attributes that are containers -- lists, dicts, non-primitive objects which hold other stuff through their __dict__s).