3

My response can be considered a follow-up to this post.

I have a dictionary that contains lists of objects. I want some function in between the copy and deepcopy functions in the copy module. I want something that performs a deep copy on built-in Python structures and primitives (integers, sets, strings, lists, etc.) but doesn't produce a deep copy of user-made objects (or non-primitive, non-aggregate objects).

It seems I might need to modify the __deepcopy__ method of my objects, but I'm not quite sure how to do this properly. A solution that does not modify an object's __deepcopy__ method is also preferable, in the event that I want to make a deep copy of the object in a future script.

Assume this is the top of my Python file:

import copy

class Obj():
    def __init__(self,i):
        self.i = i
        pass

d = {0:Obj(5),1:[Obj(6)],2:[]}
d2 = copy.deepcopy(d)

As examples, I'll list some code snippets below, along with the actual output and the desired output.

Snippet 1

d[1][0].i=7
print "d[1][0].i:",d[1][0].i,"d2[1][0].i:",d2[1][0].i
  • Actual Output: d[1][0].i: 7 d2[1][0].i: 6
  • Desired Output d[1][0].i: 7 d2[1][0].i: 7

Snippet 2

d[0].i = 6
print "d[0].i:",d[0].i,"d2[0].i:",d2[0].i
  • Actual Output: d[0].i: 6 d2[0].i: 5
  • Desired Output d[0].i: 6 d2[0].i: 6
Community
  • 1
  • 1
Matt
  • 303
  • 1
  • 2
  • 16
  • 1
    I think you'll have to substitute `__deepcopy__` or make a method of your own – unddoch Dec 06 '14 at 19:43
  • do you absolutely _need_ copies? often the best way to solve a problem like this is to avoid copying anything in the first place. – Eevee Dec 07 '14 at 05:11
  • @Eevee: The problem I'm solving an iterative one where I search through a tree of possible solutions. I build a solution incrementally (recursion is too slow for me). The root state is a dictionary of lists, and each list contains an object I defined. I need to modify the lists of temporary dictionaries I define during iteration, without modifying the root. I also need to store references to the objects instead of the objects themselves (for sake of space and functionality). – Matt Dec 07 '14 at 13:49
  • 1
    in that case you could just do `d2 = {k: v.copy() for (k, v) in d.items()}` — you know the shape of your data, so just make an explicit copy of that shape, instead of writing a more complex (and slow, and buggy) general-purpose solution – Eevee Dec 07 '14 at 23:30

2 Answers2

1

Here you go, straight from the docs:

import copy

class Obj:
    def __init__(self, i):
        self.i = i

    def __deepcopy__(self, memo):
        return self

Your last example doesn't seem right, as d3 is a shallow copy of d, therefore the list indexed by 2 should remain the same reference.

To allow for deep copying as an option, you could set some attribute in the object, and check for that in __deepcopy__.

simonzack
  • 19,729
  • 13
  • 73
  • 118
  • Good call on d3 and Snippet 3! Not sure what I was thinking when I wrote those :). I just removed that code. – Matt Dec 07 '14 at 03:43
0

You can see how the (pure python) deepcopy and copy methods are made here. You can try to make a simpler one for your specific objects or try to modify the "original".

You can also modify the __deepcopy__ method of your objects to return simply self, but that might affect their behavior - if you'd like to deepcopy them later, of course, but also if you use some external libraries, e.g. debuggers or GUI.

unddoch
  • 5,790
  • 1
  • 24
  • 37