371

I would like to create a copy of an object. I want the new object to possess all properties of the old object (values of the fields). But I want to have independent objects. So, if I change values of the fields of the new object, the old object should not be affected by that.

0

4 Answers 4

318

To get a fully independent copy of an object you can use the copy.deepcopy() function.

For more details about shallow and deep copying please refer to the other answers to this question and the nice explanation in this answer to a related question.

4
  • 2
    This answer was flagged as "Not an answer", deleted, and undeleted - meta discussion here: meta.stackoverflow.com/questions/377844/…
    – Aaron Hall
    Commented Dec 14, 2018 at 13:26
  • @AaronHall Thanks for letting me know! This certainly isn't the greatest answer I wrote, but I kind of agree with the decision that it should not be forcibly deleted. I'll brush it up a bit, but since there are already answers with all the details (notably yours), I'll keep it short. Commented Dec 14, 2018 at 15:32
  • Hi @Sven Marnach, how many "depth levels" (what nesting depth does it support) can deepcopy() copy?
    – gus
    Commented Oct 28, 2023 at 15:57
  • I asked this question recently @Sven Marnach
    – gus
    Commented Oct 28, 2023 at 15:59
158

How can I create a copy of an object in Python?

So, if I change values of the fields of the new object, the old object should not be affected by that.

You mean a mutable object then.

In Python 3, lists get a copy method (in 2, you'd use a slice to make a copy):

>>> a_list = list('abc')
>>> a_copy_of_a_list = a_list.copy()
>>> a_copy_of_a_list is a_list
False
>>> a_copy_of_a_list == a_list
True

Shallow Copies

Shallow copies are just copies of the outermost container.

list.copy is a shallow copy:

>>> list_of_dict_of_set = [{'foo': set('abc')}]
>>> lodos_copy = list_of_dict_of_set.copy()
>>> lodos_copy[0]['foo'].pop()
'c'
>>> lodos_copy
[{'foo': {'b', 'a'}}]
>>> list_of_dict_of_set
[{'foo': {'b', 'a'}}]

You don't get a copy of the interior objects. They're the same object - so when they're mutated, the change shows up in both containers.

Deep copies

Deep copies are recursive copies of each interior object.

>>> lodos_deep_copy = copy.deepcopy(list_of_dict_of_set)
>>> lodos_deep_copy[0]['foo'].add('c')
>>> lodos_deep_copy
[{'foo': {'c', 'b', 'a'}}]
>>> list_of_dict_of_set
[{'foo': {'b', 'a'}}]

Changes are not reflected in the original, only in the copy.

Immutable objects

Immutable objects do not usually need to be copied. In fact, if you try to, Python will just give you the original object:

>>> a_tuple = tuple('abc')
>>> tuple_copy_attempt = a_tuple.copy()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'copy'

Tuples don't even have a copy method, so let's try it with a slice:

>>> tuple_copy_attempt = a_tuple[:]

But we see it's the same object:

>>> tuple_copy_attempt is a_tuple
True

Similarly for strings:

>>> s = 'abc'
>>> s0 = s[:]
>>> s == s0
True
>>> s is s0
True

and for frozensets, even though they have a copy method:

>>> a_frozenset = frozenset('abc')
>>> frozenset_copy_attempt = a_frozenset.copy()
>>> frozenset_copy_attempt is a_frozenset
True

When to copy immutable objects

Immutable objects should be copied if you need a mutable interior object copied.

>>> tuple_of_list = [],
>>> copy_of_tuple_of_list = tuple_of_list[:]
>>> copy_of_tuple_of_list[0].append('a')
>>> copy_of_tuple_of_list
(['a'],)
>>> tuple_of_list
(['a'],)
>>> deepcopy_of_tuple_of_list = copy.deepcopy(tuple_of_list)
>>> deepcopy_of_tuple_of_list[0].append('b')
>>> deepcopy_of_tuple_of_list
(['a', 'b'],)
>>> tuple_of_list
(['a'],)

As we can see, when the interior object of the copy is mutated, the original does not change.

Custom Objects

Custom objects usually store data in a __dict__ attribute or in __slots__ (a tuple-like memory structure.)

To make a copyable object, define __copy__ (for shallow copies) and/or __deepcopy__ (for deep copies).

from copy import copy, deepcopy

class Copyable:
    __slots__ = 'a', '__dict__'
    def __init__(self, a, b):
        self.a, self.b = a, b
    def __copy__(self):
        return type(self)(self.a, self.b)
    def __deepcopy__(self, memo): # memo is a dict of id's to copies
        id_self = id(self)        # memoization avoids unnecesary recursion
        _copy = memo.get(id_self)
        if _copy is None:
            _copy = type(self)(
                deepcopy(self.a, memo), 
                deepcopy(self.b, memo))
            memo[id_self] = _copy 
        return _copy

Note that deepcopy keeps a memoization dictionary of id(original) (or identity numbers) to copies. To enjoy good behavior with recursive data structures, make sure you haven't already made a copy, and if you have, return that.

So let's make an object:

>>> c1 = Copyable(1, [2])

And copy makes a shallow copy:

>>> c2 = copy(c1)
>>> c1 is c2
False
>>> c2.b.append(3)
>>> c1.b
[2, 3]

And deepcopy now makes a deep copy:

>>> c3 = deepcopy(c1)
>>> c3.b.append(4)
>>> c1.b
[2, 3]
1
  • 2
    I was confused about why some objects have a copy() method, and at the same time there is a whole copy module. I know this is an old post, but thanks - I am saving the answer to review it in the future when necessary.
    – Martin
    Commented Aug 8, 2023 at 1:38
26

Shallow copy with copy.copy()

#!/usr/bin/env python3

import copy

class C():
    def __init__(self):
        self.x = [1]
        self.y = [2]

# It copies.
c = C()
d = copy.copy(c)
d.x = [3]
assert c.x == [1]
assert d.x == [3]

# It's shallow.
c = C()
d = copy.copy(c)
d.x[0] = 3
assert c.x == [3]
assert d.x == [3]

Deep copy with copy.deepcopy()

#!/usr/bin/env python3
import copy
class C():
    def __init__(self):
        self.x = [1]
        self.y = [2]
c = C()
d = copy.deepcopy(c)
d.x[0] = 3
assert c.x == [1]
assert d.x == [3]

Documentation: https://docs.python.org/3/library/copy.html

Tested on Python 3.6.5.

-1

I believe the following should work with many well-behaved classed in Python:

def copy(obj):
    return type(obj)(obj)

(Of course, I am not talking here about "deep copies," which is a different story, and which may be not a very clear concept -- how deep is deep enough?)

According to my tests with Python 3, for immutable objects, like tuples or strings, it returns the same object (because there is no need to make a shallow copy of an immutable object), but for lists or dictionaries it creates an independent shallow copy.

Of course this method only works for classes whose constructors behave accordingly. Possible use cases: making a shallow copy of a standard Python container class.

7
  • That's neat and all, but does not answer the question as your copy function fails for custom classes and the question was about objects. Commented Feb 21, 2018 at 12:55
  • @JaredSmith, it was not stated that the question was about all objects. It was not even clear if it was about deep or shallow copy (i would assume usual shallow one, but the accepted answer is about deep one). As to custom classes, if they are yours, you may just respect this kind of convention in their __init__ method. So, i thought this method may be good enough for certain purposes. In any case, I will be interested in informative comments on this suggestion.
    – Alexey
    Commented Feb 21, 2018 at 13:13
  • 1
    Consider class Foo(object): def __init__(self, arg): super(Foo, self).__init__() self.arg = arg Basic as it gets. If I do foo = Foo(3) bar = copy(foo) print(foo.arg) # 3 print(bar.arg) # <__main__.Foo object at ...> Meaning that your copy function is broken for even the most basic of classes. Again, it's a neat trick (hence no DV), but not an answer. Commented Feb 21, 2018 at 13:24
  • @JaredSmith, i saw that there is copy.copy method for making shallow copies, but, maybe naively, it seems to me that it should be the responsibility of the class to provide a "shallow copy constructor." In such case why not to provide the same kinf of interface to it as dict and list do? So, if your class wants to take responsibility for copying its objects, why not to add a if isinstance(arg, type(self)) clause into __init__?
    – Alexey
    Commented Feb 21, 2018 at 13:49
  • 2
    Because you don't always have control over the classes you use the way you do ones you define. They may, just as one example, be C programs that have Python bindings (e.g. GTK, openalpr, parts of core). Not to mention that even if you took a third party library and added copy methods to every class, how are you going to weave that into your dependency management? Commented Feb 21, 2018 at 14:05

Not the answer you're looking for? Browse other questions tagged or ask your own question.