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