Reputation: 3070
I'm using deepcopy to make a deep copy of a Python class, and change the class variable of the copied object. For some reason, the class variable of the original class that was copied is also being changed. Why is this?
It doesn't seem to happen when I create a class with the 'type' syntax.
import copy
class Test:
a = 0
print(Test.a) # 0
b = copy.deepcopy(Test)
b.a = 1
print(Test.a) # 1 - why?
c = type('Test2', (Test,), {'a': 2})
print(Test.a) # still 1
Upvotes: 2
Views: 2967
Reputation: 3722
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
Upvotes: 3
Reputation: 1223
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
Upvotes: 0