python: need a deepcopy equivalent breaking all shared identity
Question: Due to some constrains I need to create a fresh copy of an object alongwith
fresh copies of all its attributes and for attributes of its attributes and so
on recursively.

Existing deepcopy() is recursive, but when multiple objects within the tree
being copied have the same starting identity, they also have the same ending
identity (even though their ending identities don't match their starting
identities).

For the following case:

    
    
    class A:
      def __init__(self, x):
        self.x = x
    
    v = A(1)
    o = [v, v]
    

copy.deepcopy does following:

    
    
    dc_o = copy.deepcopy(o)
    assert dc_o[0] is not o[0] # new identity from the original
    assert dc_o[0] is dc_o[1]  # but maintains identity within the copied tree
    assert dc_o[0] == dc_o[1]  # ...as well as value
    

But, what I need is:

    
    
    r_dc_o = recursive_deepcopy(o)
    assert r_dc_o[0] is not o[0]      # new identity from the original
    assert r_dc_o[0] is not r_dc_o[1] # also new identity from elsewhere inside copy
    assert r_dc_o[0] == r_dc_o[1]     # while maintaining the same value
    

How can I do this?


Answer: Fully automating a recursive deepcopy in a way that _didn't_ memoize objects
would be extremely dangerous -- it would mean you couldn't have any kind of
objects with internal references preserved in a way that would make those
references useful after the copy operation (think about objects with a
"parent" link, or objects that link to a shared registry or similar resource).
That said, if you really wanted to do this (and you shouldn't -- it **will**
break a great many objects passed through the operation), you can accomplish
it by constructing a memo dictionary that ignored attempts at adding keys, and
passing that as a second argument to `deepcopy()`.

So, here we are:

    
    
    import copy
    
    class baddict(dict):
        def __setitem__(self, k, v):
            pass
    
    class A:
      def __init__(self, x):
        self.x = x
      def __eq__(self, other):
        self.x == other.x
    
    v = A(1)
    o = [v, v]
    r_dc_o = copy.deepcopy(o, baddict())
    assert r_dc_o[0] is not r_dc_o[1]
    assert r_dc_o[0] == r_dc_o[1]
    

I'd suggest thinking about _why_ you need this behavior, and trying to come up
with a better way to accomplish it. Even a `baddict` implementation that
looked at the value and skipped memoizing only if values were instances of a
specific class would be safer than what we're doing here.

