1

I am trying to use one variable containing a list of strings as base. After that I woud like to set different variables to use the base list and append their elements to the list. It should be something like: "My name is: %s", where "My name is:" is the base and the second item in the list is appended only to the second variable. I am trying to do it like this but the append adds an element to the base list as well, even though I am trying to add it to the second variable.

>>> base=["My name is:"]
>>> second_var=base
>>> second_var.append("John")
>>> print (base)
['My name is:', 'John']
>>> print (second_var)
['My name is:', 'John']

Is there a way to break the bond between the two variables?

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119

2 Answers2

2

Python variables are references to objects, so all you're doing is creating 2 references to 1 object. You need to make the second object a copy of the first before you can modify it independently of the first.

second_var = list(base)

General Explanation

Copying mutable objects in python can be tricky. If you don't do it correctly you can end up with weird bugs that are hard to identify.

>>> base = [0, 1, [2.3, 2.5], 3]
>>> # note the nested list at index 2

You can create an alias. Both variables refer to one and the same object. They have the same identity.

>>> alias = base
>>> alias is base
True

You can create a shallow copy. The 2 objects are different objects (don't have the same identity) but any mutable members will be shared between them. I can think of 4 ways to make shallow copies of lists. As far as I know, they are all functionally equivalent.

>>> method_copy = base.copy()
>>> list_copy = list(base)
>>> list_comprehension_copy = [b for b in base]
>>> from copy import copy
>>> shallow_copy = copy(base)
>>> [base is _copy for _copy in [method_copy, list_copy, list_comprehension_copy, shallow_copy]]
[False, False, False, False]
>>> [base[2] is _copy[2] for _copy in [method_copy, list_copy, list_comprehension_copy, shallow_copy]]
[True, True, True, True]

You can create a deep copy. The 2 objects will be different objects, and any mutable members will also be distinct. If you need a truly copy of a nested data structure, you want a 'deep copy'.

>>> from copy import deepcopy
>>> deep_copy = deepcopy(base)
>>> base is deep_copy
False
>>> base[2] is deep_copy[2]
False

Now let's see how they all behave when we try to append to the outer list.

>>> base.append(4)
>>> base
[0, 1, [2.3, 2.5], 3, 4]
>>> alias
[0, 1, [2.3, 2.5], 3, 4]
>>> method_copy
[0, 1, [2.3, 2.5], 3]
>>> list_copy
[0, 1, [2.3, 2.5], 3]
>>> list_comprehension_copy
[0, 1, [2.3, 2.5], 3]
>>> shallow_copy
[0, 1, [2.3, 2.5], 3]
>>> deep_copy
[0, 1, [2.3, 2.5], 3]

See how only alias updated when we appended onto base. The rest remained unchanged.

Now let's see what happens when we append to the inner list at index 2.

>>> base[2].append(2.7)
>>> base
[0, 1, [2.3, 2.5, 2.7], 3, 4]
>>> alias
[0, 1, [2.3, 2.5, 2.7], 3, 4]
>>> method_copy
[0, 1, [2.3, 2.5, 2.7], 3]
>>> list_copy
[0, 1, [2.3, 2.5, 2.7], 3]
>>> list_comprehension_copy
[0, 1, [2.3, 2.5, 2.7], 3]
>>> shallow_copy
[0, 1, [2.3, 2.5, 2.7], 3]
>>> deep_copy
[0, 1, [2.3, 2.5], 3]

See how the shallow copies all updated because they all share one-and-the-same list at index 2. Only deep_copy remained unchanged because it has its own unique copy of that inner list.

ibonyun
  • 425
  • 3
  • 11
1

In Python, Assignment statements do not copy objects, they create bindings between a target and an object. When we use = operator user thinks that this creates a new object; well, it doesn’t. It only creates a new variable that shares the reference of the original object. Sometimes a user wants to work with mutable objects, in order to do that user looks for a way to create “real copies” or “clones” of these objects. Or, sometimes a user wants copies that user can modify without automatically modifying the original at the same time, in order to do that we create copies of objects.

A copy is sometimes needed so one can change one copy without changing the other. In Python, there are two ways to create copies :

  • Deep copy (Different objects, different names)
  • Shallow copy (Same object, different names)

In your case you can use:

second_var=base.copy()

To avoid the situation. Now second_var and base will refer to separate objects in memory. You can further read about this over here.

Hamza
  • 5,373
  • 3
  • 28
  • 43