Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python deepcopy.. kind of

Is it posible to only deep copy a certain types of object, such as a list, a dict, or a tuple

Example: [[1, <SomeObj>], <OtherObj>]

I want to deep copy the first list (and of course.. the 1), but not SomeObj or OtherObj. Those should stay as refereces.

Is that possible to do that with some function that i'm not familiar with or do i have to write my own function?...

like image 462
Pwnna Avatar asked Feb 22 '23 20:02

Pwnna


2 Answers

You can do it with copy.deepcopy pretty easily by overriding the __deepcopy__ method in each of the classes you need it in. If you want different copying behavior depending on the situation, you can just set the __deepcopy__ function at runtime and then reset it:

import copy
class OtherObject(object):
    pass

l = [[1, 2, 3], [4, 5, 6], OtherObject()]
# first, save the old deepcopy if there is one
old_deepcopy = None
if hasattr(OtherObject, __deepcopy__):
    old_deepcopy = OtherObject.__deepcopy__

# do a shallow copy instead of deepcopy
OtherObject.__deepcopy__ = lambda self, memo: self
l2 = copy.deepcopy(l)
# and now you can replace the original behavior
if old_deepcopy is not None:
    OtherObject.__deepcopy__ = old_deepcopy
else:
    del OtherObject.__deepcopy__

>>> l[0] is l2[0]
False
>>> l[1] is l2[1]
False
>>> l[2] is l2[2]
True
like image 138
Daniel G Avatar answered Feb 27 '23 02:02

Daniel G


As far as I know, there's no utility to do that. The built-ins copy and deepcopy require that objects provide their own __copy__ and __deepcopy__ methods to override the default behavior. Which is not a good idea IMHO, since you don't always want the same kind of copies...

Writing a function to do that shouldn't be hard, though. Here's an example that works for lists, tuples and dicts:

def mycopy(obj):
    if isinstance(obj, list):
        return [mycopy(i) for i in obj]
    if isinstance(obj, tuple):
        return tuple(mycopy(i) for i in obj)
    if isinstance(obj, dict):
        return dict(mycopy(i) for i in obj.iteritems())
    return obj
like image 45
mgibsonbr Avatar answered Feb 27 '23 00:02

mgibsonbr