0

I am wondering why, in the following snippet, the attributes in the copied object b behave differently. b.lst yields the updated values of a.lst, but b.str remains with the original value assigned to a.str. Why is this?

>>> import copy
>>> class A(object):
...     pass
... 
>>> a = A()
>>> a.lst = [1, 2, 3]
>>> a.str = "Hola"
>>> b = copy.copy(a)
>>> a.lst.append(4)
>>> a.str = "Adios"
>>> print b.lst
[1, 2, 3, 4]
>>> print b.str
Hola
Xar
  • 7,572
  • 19
  • 56
  • 80
  • 2
    Please don't refer to lists as arrays. There are several array types in core Python: tuple, list, bytearray, and array.array, and the very popular Numpy library has arrays as well. Using the correct terminology reduces ambiguity, and makes it easier for people in the future doing searches. – PM 2Ring Jun 22 '19 at 11:45
  • 2
    The fundamental difference here isn't the difference between `str` and `list`, but the difference between the `=` operator (which rebinds the name) and the `.append` method (which simply mutates the object). If you did `a.lst = [1, 2, 3, 4]` then `b.lst` would be unaffected. – Daniel Pryden Jun 22 '19 at 11:54

1 Answers1

3

According to [Python 3.Docs]: copy.copy(x) (emphasis is mine):

Return a shallow copy of x.

To really duplicate the list (or any mutable object), use copy.deepcopy instead.

>>> import copy
>>>
>>> class A(object): pass  # In Python 3, object is extended by default
...
>>>
>>> a = A()
>>> a.lst = [1, 2, 3]
>>> a.str = "Hola"
>>>
>>> b = copy.copy(a)
>>>
>>> c = copy.deepcopy(a)
>>>
>>> a.lst.append(4)
>>> a.str = "Adios"
>>>
>>> print(b.str, b.lst)
Hola [1, 2, 3, 4]
>>>
>>> print(c.str, c.lst)
Hola [1, 2, 3]
CristiFati
  • 38,250
  • 9
  • 50
  • 87