In this question, Anthony Hatchkins gives a default implementation of deepcopy based on dict-copying code that Python falls back to:
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
I would like a default implementation based on pickling and unpickling, which Python chooses before falling back to dict-copying.
Here is my attempt, which did not work:
def __deepcopy__(self, memo):
new, args, state = self.__reduce__()
result = new(*args)
if state:
result.__setstate__(state)
memo[id(self)] = result
return result
Once I have such a method, I can make a version with additional options about what is copied and how copying is done.
The existence of reduce and and setstate are guaranteed by a base class that defines:
@staticmethod
def kwargs_new(cls, new_kwargs, *new_args):
"""
Override this method to use a different new.
"""
retval = cls.__new__(cls, *new_args, **new_kwargs)
retval.__init__(*new_args, **new_kwargs)
return retval
"""
Define default getstate and setstate for use in coöperative inheritance.
"""
def __getstate__(self):
return {}
def __setstate__(self, state):
self.__dict__.update(state)
def __getnewargs_ex__(self):
return ((), {})
def __reduce__(self):
"""
Reimplement __reduce__ so that it calls __getnewargs_ex__
regardless of the Python version.
It will pass the keyword arguments to object.__new__.
It also exposes a kwargs_new static method that can be overridden for
use by __reduce__.
"""
new_args, new_kwargs = self.__getnewargs_ex__()
state = self.__getstate__()
return (type(self).kwargs_new,
(type(self), new_kwargs,) + tuple(new_args),
state)