python笔记:赋值,浅拷贝和深拷贝
在 Python 中,变量赋值、浅拷贝和深拷贝在处理对象时有不同的行为和应用场景。以下是它们的详细区别:
1. 赋值
赋值操作只是创建了一个新的引用(别名)来指向同一个对象。也就是说,赋值操作并不创建新的对象,原始对象和赋值后的变量指向同一块内存区域。
a = [1, 2, 3]
b = a # b 是 a 的引用
b[0] = 99
print("a:", a) # 输出: [99, 2, 3]
print("b:", b) # 输出: [99, 2, 3]
如上所示,修改 b
的内容也会影响到 a
,因为它们指向同一个对象。
2. 浅拷贝
浅拷贝创建了一个新的对象,但并不递归地复制子对象。新的对象包含了对原始对象中子对象的引用,因此修改新对象的子对象也会影响到原始对象。
import copy
a = [1, 2, [3, 4]]
b = copy.copy(a) # 创建 a 的浅拷贝
b[2][0] = 99
print("a:", a) # 输出: [1, 2, [99, 4]]
print("b:", b) # 输出: [1, 2, [99, 4]]
如上所示,修改 b
的子对象也会影响到 a
,因为浅拷贝只是复制了对子对象的引用。
3. 深拷贝
深拷贝创建了一个新的对象,并且递归地复制所有的子对象。新对象和原始对象完全独立,修改新对象不会影响到原始对象。
import copy
a = [1, 2, [3, 4]]
b = copy.deepcopy(a) # 创建 a 的深拷贝
b[2][0] = 99
print("a:", a) # 输出: [1, 2, [3, 4]]
print("b:", b) # 输出: [1, 2, [99, 4]]
如上所示,修改 b
的子对象不会影响到 a
,因为深拷贝创建了完全独立的对象。
总结
- 赋值:创建一个新的引用,原始对象和新变量指向同一个对象。
- 浅拷贝:创建一个新的对象,但只复制了对象的顶层,子对象仍然是原始对象的引用。
- 深拷贝:创建一个新的对象,并递归地复制所有子对象,新对象和原始对象完全独立。
在讨论赋值、浅拷贝和深拷贝时,了解“顶层”、“层级”和“子对象”的概念很重要。这些术语有助于理解对象的结构以及不同复制方法的影响。
顶层、层级、子对象的概念
-
顶层 (Top-level):
- 顶层是指对象的第一个层级,也就是对象本身。比如,一个列表对象的顶层就是这个列表本身,而不是它包含的元素。
-
层级 (Level):
- 层级表示对象的嵌套深度。例如,一个列表中包含另一个列表,那么第一个列表是第一个层级,第二个列表是第二个层级。
-
子对象 (Sub-object):
- 子对象是指包含在另一个对象中的对象。例如,一个列表中的元素(如果这些元素也是对象)就是这个列表的子对象。
示例说明
nested_list = [1, 2, [3, 4]]
在上面的例子中:
- 顶层对象是
nested_list
这个列表。 - 第一层级包含元素
1
,2
, 和[3, 4]
。 - 元素
[3, 4]
是第二层级,它是一个子对象。
赋值、浅拷贝、深拷贝的影响
-
赋值:
- 赋值不会创建新对象,两个变量指向同一个对象。
- 修改任何层级的对象,都会影响所有引用。
a = [1, 2, [3, 4]] b = a # 赋值,a 和 b 指向同一个对象 b[2][0] = 99 # 修改子对象 print(a) # 输出: [1, 2, [99, 4]] print(b) # 输出: [1, 2, [99, 4]]
-
浅拷贝:
- 浅拷贝创建一个新的顶层对象,但子对象仍然是引用原来的对象。
- 修改顶层对象不影响原对象,但修改子对象会影响原对象。
import copy a = [1, 2, [3, 4]] b = copy.copy(a) # 浅拷贝 b[0] = 99 # 修改顶层对象 print(a) # 输出: [1, 2, [3, 4]] print(b) # 输出: [99, 2, [3, 4]] b[2][0] = 99 # 修改子对象 print(a) # 输出: [1, 2, [99, 4]] print(b) # 输出: [99, 2, [99, 4]]
-
深拷贝:
- 深拷贝创建一个新的顶层对象,并递归地复制所有子对象,生成一个完全独立的对象。
- 修改任何层级的对象都不会影响原对象。
import copy a = [1, 2, [3, 4]] b = copy.deepcopy(a) # 深拷贝 b[0] = 99 # 修改顶层对象 print(a) # 输出: [1, 2, [3, 4]] print(b) # 输出: [99, 2, [3, 4]] b[2][0] = 99 # 修改子对象 print(a) # 输出: [1, 2, [3, 4]] print(b) # 输出: [99, 2, [99, 4]]
何时使用
- 赋值: 当你不需要独立的副本,只需要多个引用来操作同一个对象时。
- 浅拷贝: 当你需要一个顶层对象的副本,但允许子对象共享时。
- 深拷贝: 当你需要一个完全独立的对象,包括所有层级的子对象都不共享时。
理解这些概念和它们的影响有助于选择适当的复制方法,以满足特定的编程需求。