5

I can't understand the following two examples of behaviour of list.append() in Python:

list_1 = ['A', 'B']
list_2 = ['C', 'D']

copy_l1 = list_1
copy_l1.append(list_2)
  1. Example

    print(copy_l1)
    

    result: ['A', 'B', ['C', 'D']]

    expected: ['A', 'B', 'C', 'D'].

    I kind of understand this, but how to get the expected result?

  2. Example

    print(list_1)
    

    result: ['A', 'B', ['C', 'D']]

    expected: ['A', 'B'].

This is the most puzzling for me. Why does copy_l1.append(list_2) also affect list_1? Due to my backgound in C, this looks to me like I'm working on pointers, but I gather that should not be the case. What means?

martineau
  • 119,623
  • 25
  • 170
  • 301
Ken Grimes
  • 258
  • 1
  • 10
  • 2
    `copy_l1 = list_1` doesn't make a copy of the list. Both variables reference the same list. – Barmar Feb 07 '22 at 18:17
  • 2
    Use `copy_l1 = list_1.copy()` – Barmar Feb 07 '22 at 18:17
  • 2
    for the first one, you want `list.extend`: `copy_l1.extend( list_2 )` –  Feb 07 '22 at 18:18
  • 2
    See [Facts and myths about Python names and values](https://nedbatchelder.com/text/names.html). – martineau Feb 07 '22 at 19:06
  • 2
    Does this answer your question? [Take the content of a list and append it to another list](https://stackoverflow.com/questions/8177079/take-the-content-of-a-list-and-append-it-to-another-list) – Tomerikoo Feb 07 '22 at 19:53

4 Answers4

6

The first result is expected as you are adding the list itself, not its values, to copy_l1. To get the desired result, use either of the following:

  • copy_l1 += list2
  • copy_l1.extend(list2)

The second result is harder to understand, but it has to do with the fact that lists are mutable in Python. To understand this, you must first understand what actually happens when you assign one variable to another.

Variable Assignment

When you use var_a = var_b, both names point to the same variable - that is, the same space in memory; they are just two different ways of accessing it. This can be tested using is, which checks for identity, not just value:

a = 1
b = a
print(a is b)
# True

So you would expect that changing the value of one name would also affect the other. However, this is not usually the case.

Changing the Value of an Immutable Variable

Most basic data types in Python are immutable. This means that their value can't actually be changed once they are created. Some examples of immutable data types are strs, ints, floats and bools.

If the data type of a variable is immutable, then its value can't be changed directly. Instead, when you alter the value of a name pointing it, this is what actually happens:

  1. A new variable is created
  2. Its value is set to the new value
  3. It is given the same name as the name which you are trying to alter - it effectively replaces it

During this process, only one name has had its value changed (or rather, replaced) and any other names pointing to the same variable stay unchanged. You can test that the actual variable the name points to has changed using is:

a = 5
b = a
print(a is b)
# True
a += 4
print(a is b)
# False

Because of this, the fact that variable assignment works the way it does can almost always be ignored. But this changes when you use mutable variables, such as lists.

Changing the Value of a Mutable Variable

Because lists are mutable, their value can actually be changed so this three-step process is not necessary. Therefore, all names pointing to the list get changed. You can see this by using is once again:

a = [1, 2]
b = a
print(a is b)
# True
a += [3, 4]
print(a is b, "again")
# True again

How to Stop this Happening

To stop this from happening, use .copy() to get a shallow copy of the list:

copy_l1 = list1.copy()

Now both names point to different variables, which happen to have the same value. Operations on one will not affect the other.

Lecdi
  • 2,189
  • 2
  • 6
  • 20
2
  1. Use .extend() rather than .append() to concatenate lists.
copy_l1.extend(list_2)
  1. You didn't make a copy of list_1, both variables refer to the same list. Use
copy_l1 = list_1.copy()

to make a shallow copy of list_1.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • I'd have thought that of all the answerers here you'd have known there'd be a zillion duplicates of this question already. You could trivially have dupe hammered it. – Martijn Pieters Dec 13 '22 at 15:02
2
list_1 = ['A', 'B']
list_2 = ['C', 'D']

copy_l1 = list_1
copy_l1.extend( list_2 )
#or
copy_l1+=list_2 
tomerar
  • 805
  • 5
  • 10
2

You use wrong ways of concatenating and coping lists.

To concatenate lists you can:

copy_l1.extend(list_2)
copy_l1 += list_2

To copy list you can:

copy_l1 = list_1.copy()
copy_l1 = list_1[:]
copy_l1 = list(list_1)
Domarm
  • 2,360
  • 1
  • 5
  • 17
Wexxan
  • 81
  • 3