Does [:] slice only make shallow copy of a list?

2020-02-05 10:57发布

I have experienced peculiar bugs from this [:] copy.

The docs say [:] makes only a shallow copy but seems:

a = [1,2,3]
id(a)
3071203276L
b=a[:]
id(b)
3071234156L

id(a) is not equal to id(b); how is that only a shallow copy?

Peculiar case:

import numpy as np
import random
a = np.array([1,2,3])
b=a[:]
random.shuffle(a)

b changes correspondingly.

标签: python numpy
5条回答
▲ chillily
2楼-- · 2020-02-05 11:43

Probably the only thing that makes a deep copy is deepcopy.

Because deep copies are expensive, as you need to track every object you copied.

Consider evil structures like this:

a = []
a.append(a)

You certainly won't want to make a naive deep copy of this.

So yes, it is a shallow copy. But in your example, it is storing primitives, which will be copied as value, not as reference. So modifying one list won't modify the other.

id() cannot be used to distinguish shallow and deep copies

It distinguishes copies from non-copies (which have the same id).

a = [1, 2, 3]
b = a
print id(b), id(a), "no surprise, same id, no copy."

Numpy arrays are different

Here, you only "shallow copy" the index, not the data which is in a backing storage. Use .copy() if you want to make sure you have a copy.

查看更多
女痞
3楼-- · 2020-02-05 11:50

Numpy defines what what a slice returns differently to the standard python library. This is because numpy is made to work with huge amounts of data. Copying these huge arrays is not always wanted, especially if the user only wanted a temporary view of the array. For instance, arr[:100].sum() sums the first 100 elements, without having to create a temporary shallow copy of the first 100 elements. Note that temporary views are only created for a basic slice.

See the documentation for more details.

查看更多
ら.Afraid
4楼-- · 2020-02-05 11:51

Numpy answer:

Arrays in numpy are views/indexes on a backing storage.

You can copy the view, without copying the backing storage...

a=numpy.array([1,2,3,4])
b=a[:] # copy of the array ("view" or "index"), not the storage
b.shape=(2,2)
print a
# [1 2 3 4]
print b
# [[1 2]
#  [3 4]]
b *= 2
print a
# [2 4 6 8]
print b
# [[2 4]
#  [6 8]]

See how changing b affected a? Yet they still have a different shape. Consider them to be views of the data; and the b=a[:] line copied just this view. I could even modify the shape of b. Because it is just an index to the data, that says where columns and rows are located in memory.

If you want a copy of the backing storage in numpy, use a.copy().

查看更多
乱世女痞
5楼-- · 2020-02-05 11:56

It is a shallow copy, but changing b does not affect a in this case because the elements are just numbers. If they were references then a would be updated:

a = [1, 2, 3]
b = a[:]

b[1] = 5
print "a: ", a
print "b: ", b
# a: [1, 2, 3]
# b: [1, 5, 3]

vs

a = [[1], [2], [3]]
b = a[:]

b[1][0] = 5
print "a: ", a
print "b: ", b
# a:  [[1], [5], [3]]
# b:  [[1], [5], [3]]
查看更多
霸刀☆藐视天下
6楼-- · 2020-02-05 11:56

The difference is that the elements of list a and list b are the same. Changing mutable objects in either list also effects the elements in the other list.

In contrast there is deepcopy which tries to create a completely different set of objects.

查看更多
登录 后发表回答