为什么浅拷贝表现为简单列表的深拷贝

Why does shallow copy behaves as deep copy for a simple list

我打算在 python 中了解浅拷贝和深拷贝的概念。我观察到大多数 posts/blogs/SO answer 解释这些概念都是使用嵌套列表。

import copy
lst = [[1,2,3],[4,5,6]]
b = copy.copy(lst)
c = copy.deepcopy(lst)

# Shallow copy demo
b[0][0] = 9
print(b)
# >>> [[9, 2, 3], [4, 5, 6]]
print(lst)    
# >>> [[9, 2, 3], [4, 5, 6]]

# Deepcopy demo
c[0][0] = 10
print(c)
# >>> [[10, 2, 3], [4, 5, 6]] 
print(lst)
# >>> [[9, 2, 3], [4, 5, 6]]

通过上面的简单例子,我理解了浅拷贝和深拷贝的概念。但是当我实现这个概念时,在一个简单的列表(一维列表)上,观察到浅拷贝表现得像深拷贝。

import copy
lst = [1,2,3]
b = copy.copy(lst)
c = copy.deepcopy(lst)

# Shallow copy demo
b[0] = 0
print(b)
# >>> [0, 2, 3]
print(lst)
# >>> [1,2,3]

# Deepcopy demo
c[0] = 9
print(c)
# >>> [9,2,3]
print(lst)
# >>> [1,2,3]

这表明 copy.copy(lst) 的行为不同,并且进行深拷贝而不是浅拷贝。

我想了解,为什么 copy.copy() 的行为对于嵌套列表和简单列表是不同的。另外,如果我必须为简单列表获取浅拷贝,我该如何实现呢?

您得到的结果与 "level of depth" 没有直接关系, 这里要记住的最重要的事情是 mutabiliy.

的概念

列表是可变的,同时数值不是。这意味着您可以添加或修改列表中的项目,但这些操作不会创建或破坏列表,它们只会更改列表。您可以使用内置函数 id() 来验证,它会为您提供变量的内存地址:

lst = [1, 2, 3]
print(id(lst)) # the number printed by this...
lst.append(4)
lst[1] = 0
print(id(lst)) # should be the same printed by this one. That tells us that 
               # the variable 'lst' keeps referecing the same object, although
               # the object have changed in form (mutated)

数字完全不同,这是有道理的,因为数字类型变量只能 存储单个数值:

a = 5
print(id(a)) # the number printed by this...
a = 6
print(id(a)) # should be different than this one, meaning that a new numeric 
             # value were created and stored in a different memory address

在线

b[0][0] = 9

在您的第一个示例中,b[0] 处的列表正在被操作,但它仍然是同一个对象,并且由于 b[0] 只不过是对 [= 处相同列表的引用16=](因为b是一个浅拷贝),当我们打印lst时我们会看到它也改变了。

在您的实现中,当您分配 b[0] = 0 时,python 正在创建值 0,将其存储在新的内存位置,并覆盖 [=14= 的引用] 必须与 lst[0] 具有相同的值(因为那是数字类型的自然行为)。

如前所述,这不一定与复合数据结构的嵌套级别有关, 因为其中一些是不可变的(例如元组),并且在您的实现中发生的相同情况也会发生在这个不可变的数据结构上。

您可以阅读更多关于 id() 内置函数 here 的内容,以及更多关于 可变和不可变类型 here

希望这个回答对您有所帮助!