How to override the copy/deepcopy operations for a Python object?
python, python-internals
Solution
The recommendations for customizing are at the very end of the docs page:
Classes can use the same interfaces to control copying that they use to control pickling. See the description of module pickle for information on these methods. The copy module does not use the copy_reg registration module.
In order for a class to define its own copy implementation, it can define special methods `__copy__()` and `__deepcopy__()`. The former is called to implement the shallow copy operation; no additional arguments are passed. The latter is called to implement the deep copy operation; it is passed one argument, the memo dictionary. If the `__deepcopy__()` implementation needs to make a deep copy of a component, it should call the `deepcopy()` function with the component as first argument and the memo dictionary as second argument.
Since you appear not to care about pickling customization, defining `__copy__` and `__deepcopy__` definitely seems like the right way to go for you.
Specifically, `__copy__` (the shallow copy) is pretty easy in your case...:
def __copy__(self):
newone = type(self)()
newone.__dict__.update(self.__dict__)
return newone
`__deepcopy__` would be similar (accepting a `memo` arg too) but before the return it would have to call `self.foo = deepcopy(self.foo, memo)` for any attribute `self.foo` that needs deep copying (essentially attributes that are containers -- lists, dicts, non-primitive objects which hold other stuff through their `__dict__`s).
Problem
I understand the difference between `copy` vs. `deepcopy` in the copy module. I've used `copy.copy` and `copy.deepcopy` before successfully, but this is the first time I've actually gone about overloading the `__copy__` and `__deepcopy__` methods. I've already Googled around and looked through the built-in Python modules to look for instances of the `__copy__` and `__deepcopy__` functions (e.g. `sets.py`, `decimal.py`, and `fractions.py`), but I'm still not 100% sure I've got it right. Here's my scenario: I have a configuration object. Initially, I'm going to instantiate one configuration object with a default set of values. This configuration will be handed off to multiple other objects (to ensure all objects start with the same configuration). However, once user interaction starts, each object needs to tweak its configurations independently without affecting each other's configurations (which says to me I'll need to make deepcopys of my initial configuration to hand around). Here's a sample object: ``` class ChartConfig(object): def __init__(self): #Drawing properties (Booleans/strings) self.antialiased = None self.plot_style = None self.plot_title = None self.autoscale = None #X axis properties (strings/ints) self.xaxis_title = None self.xaxis_tick_rotation = None self.xaxis_tick_align = None #Y axis properties (strings/ints) self.yaxis_title = None self.yaxis_tick_rotation = None self.yaxis_tick_align = None #A list of non-primitive objects self.trace_configs = [] def __copy__(self): pass def __deepcopy__(self, memo): pass ``` What is the right way to implement the `copy` and `deepcopy` methods on this object to ensure `copy.copy` and `copy.deepcopy` give me the proper behavior?