python-3.x - 为什么浅拷贝表现为简单列表的深拷贝

标签 python-3.x deep-copy shallow-copy

我打算了解 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() 的行为对于嵌套列表和简单列表是不同的。另外,如果我必须为简单列表获取浅拷贝,我该如何实现呢?

最佳答案

您得到的结果与“深度级别”没有直接关系, 这里要牢记的最重要的事情是可变性的概念。

列表是可变的,同时数值不是。这意味着您可以添加或修改列表中的项目,但这些操作不会创建或破坏列表,它们只会更改它。您可以使用内置函数 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] 仅此而已而不是对 lst[0] 中相同列表的引用(因为 b 是浅拷贝),当我们打印 lst 时,我们将看到它也改变了。

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

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

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

希望这个回答对你有帮助!

关于python-3.x - 为什么浅拷贝表现为简单列表的深拷贝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59025868/

相关文章:

python - 一维列表与二维列表中的浅复制

c++ - 我可以阻止复制构造函数有一些异常(exception)吗?

python - CV2 OpenCL,cv2.UMat 对象不可迭代

python - AysncResult 和 python 池中 error_callback 回调之间的区别

python - Python 的 Deoptim 优化器

c++ - 如何为包含 shared_ptr 的类创建复制构造函数/赋值运算符? C++

java - 如何深度复制二维数组(不同的行大小)

python - 程序如何在python中的两个函数之间进行选择?

python - Python 中双向链表的深拷贝

java - android中 Intent 中对象的浅拷贝