LambdaLabTM
Computer Science · Class 11 · Data Types
ListsSharing⏱️ 12 min read

Sharing & Copying

This whole lesson is about one line: b = a. It looks like it makes a copy. It never does. It gives the value that is already there a second name. Whether that matters to your program depends on one thing you already know — whether the value can be changed. So the lesson comes in two parts — A for the objects that can be changed, B for the ones that cannot.

1The one rule

An = writes a label on a box. That is all it does. It builds a new value only when the right side is something that has to be worked out, like 2 + 3 or [10, 20].

In b = a the right side is just a name. There is nothing to work out and nothing to build. a leads to a box, and the label b is written on that same box:

After b = a
a
b
[10, 20, 30]

One value. Both names lead here.

This happens for every type. A list, a number, a string — b = a shares all of them. What changes from one type to the next is only what can happen next:

Mutable objects
Lists — sharing you can feel

A list can be edited in place. So a change made through one name is a change the other name sees. Sometimes useful, sometimes a disaster.

→ Part A, next
Immutable objects
Numbers, strings, tuples — sharing you cannot feel

Nothing can edit these, so a shared value can never change under you. The sharing is real, and it is harmless.

→ Part B, later
Part A starts here · mutable objects
Sharing a value that can change

Lists, dictionaries and sets. Here the second name matters.

2b = a gives one list two names

second_name.py
a = [10, 20, 30]
b = a              # a second NAME — not a copy

b.append(40)

print('a:', a)
print('b:', b)
Output
a: [10, 20, 30, 40]
b: [10, 20, 30, 40]

One append, and both names show four items. There are not two lists here to disagree with each other. There is one list wearing two labels.

3Where it hurts: the backup that is not a backup

Here is the same line written with the opposite intention. It does the opposite of what the name promises:

fake_backup.py
original = [5, 3, 9]
backup = original          # meant as a backup — it is not one

original.sort()

print('original:', original)
print('backup  :', backup)
Output
original: [3, 5, 9]
backup  : [3, 5, 9]
Watch Out
The backup was sorted too, because it was never a backup. Calling a name backup does not make a second list. Sorting through original sorted the one list both names lead to.

4Taking a real copy

To get a second list you have to build one. Any of these three does it — pick whichever reads best to you:

three_copies.py
a = [10, 20, 30]

b = a[:]           # a slice of the whole list
c = list(a)        # build a new list out of it
d = a.copy()       # the method made for this job

a.append(99)

print('a:', a)
print('b:', b)
print('c:', c)
print('d:', d)
Output
a: [10, 20, 30, 99]
b: [10, 20, 30]
c: [10, 20, 30]
d: [10, 20, 30]
a[:]
The whole-list slice

A slice always builds a new list, and a slice with no start and no stop is all of it.

list(a)
The list() function

Builds a list out of any sequence. The one to reach for when the original is a tuple or a string.

a.copy()
The copy() method

A list method that does this one job. It says what it means, so it reads the clearest.

Now the backup keeps its promise:

real_backup.py
original = [5, 3, 9]
backup = original[:]       # a real copy

original.sort()

print('original:', original)
print('backup  :', backup)
Output
original: [3, 5, 9]
backup  : [5, 3, 9]

5Both of them, on the memory wall

Two programs, almost the same. The only difference in the code is a against a[:], and the wall shows why the results are nothing alike. Run each one line by line and watch how many boxes appear:

a = [10, 20, 30]
b = a
b.append(40)
print(a)
Screen
Memory (RAM)
Press Run line 1 and watch the memory wall on the right. Nothing exists there yet — the boxes only appear when an = runs.
Key Takeaway
Count the boxes, not the names. b = a adds a label and leaves one box, so editing through either name changes what both names see. b = a[:] builds a second box, so the names go their own way. Everything in this lesson comes back to that count — and the next section is how you ask Python for it.

6Sharing is not always a mistake

Sometimes a second name for one list is exactly what you want — a short name to work through, when the work should land on the real list:

short_name.py
marks = [78, 85, 62, 91]
m = marks                  # a short name for the same list

m.sort()

print(marks)
Output
[62, 78, 85, 91]

marks came out sorted, which is the point. Had m been a copy, the sort would have landed on the copy and the real list would still be in its old order.

Between the two parts
How to ask Python which one you have

Part A was about when a copy is made and when it is not. Here is the test that answers it in code — and you will need it in Part B.

7Asking Python which one you have — == and is

You have just watched the boxes appear on the wall. In a real program you cannot see them, so Python gives you two operators, and they ask two different questions:

==
Are the two values equal?

Looks at the contents. Two different lists holding the same numbers are equal, and == says so. This is the one you want almost every time.

is
Is it the same box?

Ignores the contents completely. It asks whether the two names lead to one box, or to two boxes that happen to match.

Which makes is the exact question this lesson has been asking all along. Here are both programs from Part A, with the check added:

which_is_it.py
a = [10, 20, 30]
b = a              # a second name

print(a == b, a is b)

c = [10, 20, 30]
d = c[:]           # a real copy

print(c == d, c is d)
Output
True True
True False

Read the second column. True means one box with two labels on it; False means two boxes. The first column says True both times, because the contents match either way — which is exactly why == cannot answer this question and is can.

is not and !=

Each one has its opposite, and the opposites keep the same split: != compares values, is not compares boxes.

opposites.py
a = [1, 2]
b = [1, 2]

print(a is not b)   # two different lists — True
print(a != b)       # but their contents match — False
Output
True
False
OperatorAsksTrue when
==are the values equal?the contents match
!=are the values different?the contents do not match
isis it the same box?both names lead to one box
is notis it a different box?the names lead to two boxes

8Which one should you write?

Almost always ==. You nearly always want to know whether two things match, not whether they are one box. There is one place where is is the normal thing to write, and that is with None:

checking_none.py
marks = None
print(marks is None)

marks = []
print(marks is None)
print(marks is not None)
Output
True
False
True

There is only ever one None in a running Python program, so asking “is this that one None?” is exactly the right question. You will see is None constantly in real code.

Watch Out
Never use is to compare numbers or strings. It sometimes appears to work, which is what makes it dangerous. Whether Python keeps one copy of an equal value or two is its own private business, and it changes with how the value was made:
dont_do_this.py
a = 1000
b = 1000          # typed out, same as a
c = a + 0         # worked out while the program runs

print(a == b, a is b)
print(a == c, a is c)
Output
True True
True False

a, b and c all hold 1000, and == says so every time. is gives two different answers to the same question, because it was never asking about the value in the first place.

And it is not even settled from one run to the next: type those same three lines at the >>> prompt instead of saving them in a file, and a is b comes out False. Python may keep one copy of an equal immutable value and it may keep two — that choice is its own, it can differ, and no correct program should ever depend on it. Use == for values, and keep is for None — and for the one job it does here, telling a second name from a real copy.

Part B starts here · immutable objects
Sharing a value that cannot change

Numbers, strings, tuples. Here the second name is harmless.

9The same line, with a number

Try it with an integer, and nothing alarming happens:

with_a_number.py
a = 10
b = a              # b points at the same 10

a = a + 1          # a NEW number — a moves onto it

print('a:', a)
print('b:', b)
Output
a: 11
b: 10

It is tempting to say b kept 10 because it was a copy. It was not. b = a shared the 10 here exactly as it shared the list. The difference is the next line. You cannot edit a 10 (which is immutable) into an 11, so a = a + 1 had no choice: it built a new number and moved a onto it. b was never asked to move.

A string does the same thing. Watch both on the wall — the first step of each is the shared box you saw in Part A:

a = 10
b = a
a = a + 1
print(a)
print(b)
Screen
Memory (RAM)
Press Run line 1 and watch the memory wall on the right. Nothing exists there yet — the boxes only appear when an = runs.
Key Takeaway
The danger was never sharing. It is sharing something that can be edited. Two names on one list can surprise you, because append, sort, remove and a[0] = … all edit the one list. Two names on one number, string or tuple can never surprise you, because nothing in Python can edit those.

10So you never copy an immutable value

There is no reason to. Nothing can be changed behind your back, so a second name is as good as a second value. Python agrees so strongly that slicing a whole tuple does not even bother to build anything — it hands the same tuple straight back:

tuple_slice.py
t = (10, 20, 30)
u = t[:]

print(u)
print(t is u)      # the very same tuple
Output
(10, 20, 30)
True

The same slice on a list always builds a new list, because with a list it makes a real difference. That is the whole story in one line of code.

11Typed twice: one box, or two?

There is one more question, and the two parts of this lesson answer it differently. Write the same value on two separate lines. Does Python store it once and put both names on it, or store it twice?

typed_twice.py
a = 10
b = 10
print(a is b)          # one 10, or two? Python decides

x = [10, 20, 30]
y = [10, 20, 30]
print(x is y)          # never one list

x.append(40)
print('x:', x)
print('y:', y)
Output
True
False
x: [10, 20, 30, 40]
y: [10, 20, 30]

The number: Python may share, and it makes no difference

For 10, Python is free to do either — keep one 10 in memory with both labels on it, or build a second one. Here it kept one, so a is b came out True. With a different value it might not, and there is nothing in your code that decides it.

And you never need to know, because nothing can edit a 10. One copy or two, a and b both read 10 for as long as they exist. There is no danger in sharing a value that cannot be modified — which is exactly why Python is allowed to save the memory.

The list: Python must not share, so it never does

With lists that freedom disappears. Suppose Python did save memory here and quietly kept one list for both x and y. Then this is what your program would do:

if_python_shared.py
x = [10, 20, 30]
y = x              # pretend Python had quietly shared them

y.append(40)       # a change meant for y alone

print('x:', x)
print('y:', y)
Output
x: [10, 20, 30, 40]
y: [10, 20, 30, 40]

You asked for a change to y and got a change to x as well — a list you never mentioned, changed by accident, in a program that looks correct. A list is mutable, so sharing one behind your back would be a trap. That is why Python never does it: every [ ] you type is an instruction to build a list, and it is obeyed every time.

Key Takeaway
Sharing is safe only when nothing can be changed. Equal immutable values may quietly share one box, because no line of code could ever tell the difference. Equal lists never do — two lists typed out separately are always two lists. The only way to get one shared list is to ask for it with b = a.
try_sharing.py

12Recap

b = a is a second name

Never a copy. The label goes on the box that is already there — for every type in Python.

With a list, you feel it

One box, two labels. append or sort through either name and both names see it. a is b is True.

backup = original is not a backup

Naming a label backup does not build a second list. Sorting the original sorts the 'backup' too.

a[:], list(a), a.copy()

Three ways to build a genuine second list. After any of them, a change to one leaves the other alone.

== compares values, is compares boxes

a is b is True for a second name and False for a copy — the quickest way to tell which you have. Keep is for None, and never use it on numbers or strings.

With a number or a string, you cannot feel it

The sharing is just as real. But nothing can edit the value, so a = a + 1 has to build a new one and move only a.

Typed twice: numbers may share, lists never do

Two equal numbers may sit in one box, because nothing can edit them. Two equal lists are always two lists — sharing them would let a change meant for one land on the other.

✍️ Now write these yourself
  1. 1

    Make b = a, append through b, and print both.

    Hint · Both show the new item. There is only one list.

  2. 2

    Do the same with b = a[:] and compare the two results.

    Hint · Now only b changes, because the slice built a second list.

  3. 3

    Print a is b after each of those two lines.

    Hint · True for the second name, False for the copy. That check is the quickest way to tell which you have.

  4. 4

    Write the fake backup, sort the original, and watch the backup get sorted with it.

    Hint · Then fix it with original[:] and run it again.

  5. 5

    Make p = 'hello', then q = p, then p = 'bye'. Print both.

    Hint · q still says hello. The second assignment moved p onto a new string and left q behind.

Quick Check

After a = [1, 2] and b = a, what does b.append(3) do to a?

Quick Check

Which line gives you a genuine second list?

Quick Check

After b = a on a list, what do a == b and a is b give?

Quick Check

Which comparison should you write to check whether marks holds None?

Quick Check

Why does b keep the old value after a = a + 1, when a and b shared one 10?

Quick Check

After x = [10, 20] and y = [10, 20], what does x is y give?

Quick Check

Why is Python allowed to store one 10 for both a = 10 and b = 10, but never one list for x = [1] and y = [1]?

Quick Check

Why is there no point copying a tuple?