Reputation: 1442
I'd like to create a class which can provide a list of attributes which are not deepcopied by copy.deepcopy()
. For example like this:
class CustomDeepcopy(object):
a = SomeSimpleObject()
b = SomeBigObject()
def dont_deepcopy(self):
return ['b']
def __deepcopy__(self,memo):
#Somehow call copy.deepcopy(self) and have it
#deepcopy self.a but not self.b
#
#For example, this *almost* works,
for attr in self.dont_deepcopy():
val = getattr(self,attr,None)
if val is not None:
memo[id(val)]=val
return copy.deepcopy(self,memo)
The problem is that I don't think I can call copy.deepcopy()
from within __deepcopy__()
because that leads to an infinite recursion (since copy.deepcopy()
first checks if my object has a __deepcopy__()
method). Is there any way I can do this?
Upvotes: 4
Views: 1948
Reputation: 157
copy.deepcopy
will only call __deepcopy__
if the method exists - we can avoid this by saving the value of __deepcopy__
, calling copy.deepcopy(...)
, and then restoring the value of __deepcopy__
before returning the result:
class CustomDeepcopy(object):
a = SomeSimpleObject()
b = SomeBigObject()
def dont_deepcopy(self):
return ['b']
def __deepcopy__(self,memo):
for attr in self.dont_deepcopy():
val = getattr(self,attr,None)
if val is not None:
memo[id(val)]=val
deepcopy_method = self.__deepcopy__
self.__deepcopy__ = None
result = copy.deepcopy(self,memo)
self.__deepcopy__ = deepcopy_method
return result
Upvotes: 2
Reputation: 17096
Any time you implement a special method (like __getattr__
, __deepcopy__
, __str__
, etc.) You either need to go up the mro with super or use some subset of the original.
I'm not totally clear how you're memoizing attributes, but I'm going to simplify your example. Let's say you always use the same a (and that it's immutable and doesn't need to be copied), but otherwise, you want to copy b. (and you can pass a
and b
directly to the constructor to make a new object.
class CustomDeepcopy(object):
def __init__(self, a=None, b=None):
if a:
self.a = a
if b:
self.b = b
a = SomeSimpleObject()
b = SomeBigObject()
@property
def dont_deepcopy(self):
return ['b']
@property
def deepcopy_attributes(self):
return ['a']
def __deepcopy__(self,memo):
new_kwargs = dict((k, getattr(self, attr, None)) for attr in self.dont_deepcopy)
for attr in self.deepcopy_attributes:
new_kwargs[attr] = copy.deepcopy(getattr(self, attr, None))
return self.__class__(**new_kwargs)
Upvotes: 1