Best way to partially deep copy a dictionary in Python?
Question: I have a graph that is represented as a `dict` where each key is an instance
of a (self-defined) `Node` class and the values are sets of instances of
`Nodes`. So, basically, the graph looks something like this, but way larger:

`g = { Node1 : {Node2, Node3}, Node2 : {Node4}, Node3: set(), Node4 : {Node1}
}`

**In very short words of what I want to do:** I want to arbitrarily change a
dictionary and then revert it to its original value before those changes.

I have a series of transformations that I can make to this graph, but I don't
have any possible way of knowing beforehand which transformation that I want
to do. The transformation will always:

  * Delete one key
  * Add in two new vertices
  * Change about 1/n edges 

Since I don't know which transformation I want to do, I want to perform every
transformation to the same graph and then pick one.

An obvious idiom could be:

  * Copy the dictionary to a temporary dictionary (`temp = g`)
  * Repeat for each transformation `t`: 
    * Perform a transformation `t` on the graph `g` to form the graph `g'`
    * Jot down information about the graph `g'` for later
    * Set `g = temp` to restore the graph to the known-good state

This does not work because copying the dictionary only performs a shallow
copy, so all changes to `g` are also performed on `temp`.

I can use `deepcopy`, but even that cannot work as is. I want to `deepcopy`
the actual dictionary `g`, but the keys and elements in the values of `g` (the
`Nodes`) cannot be deepcopied, because in my transformation, I will look for
elements that are in `g` but not in `temp` because they are now new objects.

I can attempt to redefine `deepcopy` for the `Node` class, which _works_ , but
it is very hackish and I _do_ need to use deepcopy to perform my
transformations `t`.

Following is a minimal working example that does what I want it to do -- but
in a way that I _do not want to_ because then I need to create a workaround
for making deepcopy actually work when I need it to. Also, the code to do the
transformations is all using `g` and the actual `Nodes` in `g` as it stands
right now, so not having to change much of that would be nice.

Is there a better way to do this? (all `print`s should be `True`)

    
    
    from copy import deepcopy
    
    class MyClass:
    
        def __init__(self, value):
            self.value = value
    
        def __repr__(self):
            return str(self.value)
    
        def __deepcopy__(self, memo):
        # do not rly deep copy plx
            return self
    
        class1 = MyClass(1)
        class2 = MyClass(2)
        class3 = MyClass(3)
    
        dict_class = { class1 : {class2, class3}, class2 : {class3}, class3 : {class1}}
    
        #### Want to create a copy of the dictionary with exact same objects... ####
    
        dict_class_copy = deepcopy(dict_class)
    
        print(dict_class)
        print(dict_class_copy)
    
        print(class1 in dict_class and class2 in dict_class and class3 in dict_class)
        print(class1 in dict_class_copy and class2 in dict_class_copy and class3 in dict_class_copy)
    
        dict_class.pop(class2)
        dict_class[class1].remove(class3)
    
        # don't want to change original dictionary key values
        print(class2 not in dict_class and class2 in dict_class_copy)
    
        # this breaks w/o deepcopy!
        print(class3 not in dict_class[class1] and class3 in dict_class_copy[class1])
    
        # reassign it back 
        dict_class = dict_class_copy 
    
        # i want this back!
        print(class2 in dict_class)
        print(class3 in dict_class[class1])
    


Answer: Make a "1 level deep" copy of the dict by copying the keys and making copies
of the sets. Replace this:

    
    
    dict_class_copy = deepcopy(dict_class)
    

with this:

    
    
    dict_class_copy = {k:set(v) for k,v in dict_class.items()}
    

and your tests pass.

