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:
b = aab[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:
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.
Nothing can edit these, so a shared value can never change under you. The sharing is real, and it is harmless.
Lists, dictionaries and sets. Here the second name matters.
2b = a gives one list two names
a = [10, 20, 30]
b = a # a second NAME — not a copy
b.append(40)
print('a:', a)
print('b:', b)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:
original = [5, 3, 9]
backup = original # meant as a backup — it is not one
original.sort()
print('original:', original)
print('backup :', backup)original: [3, 5, 9] backup : [3, 5, 9]
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:
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)a: [10, 20, 30, 99] b: [10, 20, 30] c: [10, 20, 30] d: [10, 20, 30]
a[:]A slice always builds a new list, and a slice with no start and no stop is all of it.
list(a)Builds a list out of any sequence. The one to reach for when the original is a tuple or a string.
a.copy()A list method that does this one job. It says what it means, so it reads the clearest.
Now the backup keeps its promise:
original = [5, 3, 9]
backup = original[:] # a real copy
original.sort()
print('original:', original)
print('backup :', backup)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:
= runs.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:
marks = [78, 85, 62, 91]
m = marks # a short name for the same list
m.sort()
print(marks)[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.
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:
==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.
isIgnores 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:
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)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.
a = [1, 2]
b = [1, 2]
print(a is not b) # two different lists — True
print(a != b) # but their contents match — FalseTrue False
| Operator | Asks | True when |
|---|---|---|
== | are the values equal? | the contents match |
!= | are the values different? | the contents do not match |
is | is it the same box? | both names lead to one box |
is not | is 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:
marks = None
print(marks is None)
marks = []
print(marks is None)
print(marks is not None)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.
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: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)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.
Numbers, strings, tuples. Here the second name is harmless.
9The same line, with a number
Try it with an integer, and nothing alarming happens:
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)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:
= runs.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:
t = (10, 20, 30)
u = t[:]
print(u)
print(t is u) # the very same tuple(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?
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)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:
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)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.
b = a.12Recap
Never a copy. The label goes on the box that is already there — for every type in Python.
One box, two labels. append or sort through either name and both names see it. a is b is True.
Naming a label backup does not build a second list. Sorting the original sorts the 'backup' too.
Three ways to build a genuine second list. After any of them, a change to one leaves the other alone.
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.
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.
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.
- 1
Make
b = a, append throughb, and print both.Hint · Both show the new item. There is only one list.
- 2
Do the same with
b = a[:]and compare the two results.Hint · Now only
bchanges, because the slice built a second list. - 3
Print
a is bafter each of those two lines.Hint ·
Truefor the second name,Falsefor the copy. That check is the quickest way to tell which you have. - 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
Make
p = 'hello', thenq = p, thenp = 'bye'. Print both.Hint ·
qstill says hello. The second assignment movedponto a new string and leftqbehind.
After a = [1, 2] and b = a, what does b.append(3) do to a?
Which line gives you a genuine second list?
After b = a on a list, what do a == b and a is b give?
Which comparison should you write to check whether marks holds None?
Why does b keep the old value after a = a + 1, when a and b shared one 10?
After x = [10, 20] and y = [10, 20], what does x is y give?
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]?
Why is there no point copying a tuple?