Python: deepcopy does not work on user-defined classes?
Question:
In the following example I would expect deepcopy to create a copy of field and not just copy the reference. What happens here and is there an easy way around it?
from copy import deepcopy
class Test:
field = [(1,2)]
t1 = Test()
t2 = deepcopy(t1)
t2.field[0]=(5,10)
print t1.field # [(1,2)] expected but [(5,10)] obtained
print t2.field # [(5,10)] expected
Output:
[(5, 10)]
[(5, 10)]
Answers:
Deep copying (by default) only applies to instance level attributes – not class level – It doesn’t make much sense that there’s more than one unique class.attribute
…
Change your code to:
class Test:
def __init__(self):
self.field = [(1,2)]
Another approach with python 3.8 (I am not sure about previous versions) could be creating a __init__
method that deep-copies every class level attribute, like:
from copy import deepcopy
class Test:
field = [(1,2)]
def __init__(self):
for attr in dir(self):
if not attr.startswith('_'):
setattr(self, attr, deepcopy(getattr(self, attr)))
t1 = Test()
t2 = deepcopy(t1)
t2.field[0]=(5,10)
print(t1.field) # [(1,2)]
print(t2.field) # [(5,10)]
of course you can also replace the dir
with inspect.getmembers
.
In the following example I would expect deepcopy to create a copy of field and not just copy the reference. What happens here and is there an easy way around it?
from copy import deepcopy
class Test:
field = [(1,2)]
t1 = Test()
t2 = deepcopy(t1)
t2.field[0]=(5,10)
print t1.field # [(1,2)] expected but [(5,10)] obtained
print t2.field # [(5,10)] expected
Output:
[(5, 10)]
[(5, 10)]
Deep copying (by default) only applies to instance level attributes – not class level – It doesn’t make much sense that there’s more than one unique class.attribute
…
Change your code to:
class Test:
def __init__(self):
self.field = [(1,2)]
Another approach with python 3.8 (I am not sure about previous versions) could be creating a __init__
method that deep-copies every class level attribute, like:
from copy import deepcopy
class Test:
field = [(1,2)]
def __init__(self):
for attr in dir(self):
if not attr.startswith('_'):
setattr(self, attr, deepcopy(getattr(self, attr)))
t1 = Test()
t2 = deepcopy(t1)
t2.field[0]=(5,10)
print(t1.field) # [(1,2)]
print(t2.field) # [(5,10)]
of course you can also replace the dir
with inspect.getmembers
.