Python赋值、浅拷贝与深拷贝机制详解
本文详细解析Python中变量赋值、浅拷贝与深拷贝的核心机制。通过对比不可变类型(如字符串)和可变对象(如列表)在三种操作下的内存ID变化,阐明引用传递与对象复制的区别。重点说明浅拷贝仅复制顶层对象而共享嵌套子对象,深拷贝则完全独立复制所有层级元素,帮助开发者避免常见的内存引用错误。
在深入讨论之前,需要明确几个核心概念。
不可变类型指的是那些在内存中一旦创建,其值就无法被修改的数据类型。
当尝试改变不可变类型的值时,由于原有内存中的值不可更改,Python会复制原值并开辟一段新的内存空间来存储这个新值。
可变类型则是指那些在对象指定的内存地址上,其值可以被直接修改的数据类型。
对于可变类型,当变量被修改时,其指向的内存地址上的值会直接被更新,不会发生值的复制,也不会开辟新的内存空间。
- 变量是系统表中的一个元素,它拥有指向具体对象的连接空间。
- 对象是被分配的一块内存区域,用于存储其所代表的实际值。
- 引用则是自动形成的从变量到对象的指针连接。
当在代码编辑器中编写赋值语句时,
test = 'python'
Python解释器会执行以下操作:
首先创建变量名,
接着创建一个对象(即分配一块内存)来存储具体的Python值,
然后将变量与该对象通过指针
链接起来,这种从变量到对象的连接过程被称为引用(即变量引用对象)。

赋值操作仅仅是复制了新对象的引用,而不会开辟新的内存空间。
这意味着赋值后的变量与原对象指向同一块内存地址。

浅拷贝是指拷贝父对象,但不会拷贝对象内部的子对象。
具体来说,浅拷贝产生的对象本身是新的(拥有独立的内存地址),但其内容并非全新复制,而是对原对象元素的引用。
浅拷贝的本质是将存放变量的地址值传递给被赋值对象,导致最终两个变量引用了同一份地址(针对顶层对象)。
注意:对于不可变类型,无论进行何种拷贝,其ID地址通常保持一致,因为不可变对象本身不支持原地修改。

深拷贝则拷贝了对象的所有元素,包括多层嵌套的子对象。
深拷贝出来的对象是一个完全全新的对象,不再与原来的对象有任何关联。因此,对原对象进行的任何修改都不会影响已经深拷贝出来的新对象。

以下是针对不可变对象的深浅拷贝示例代码及结果分析。
import copy
test = 'abc'
print("=====赋值=====")
b=test
print(test)
print(b)
print(id(test))
print(id(b))
print("=====浅拷贝=====")
b=copy.copy(test)
print(test)
print(b)
print(id(test))
print(id(b))
print("=====深拷贝=====")
b=copy.deepcopy(test)
print(test)
print(b)
print(id(test))
print(id(b))
运行结果如下: =====赋值===== abc abc 1855476943856 1855476943856 =====浅拷贝===== abc abc 1855476943856 1855476943856 =====深拷贝===== abc abc 1855476943856 1855476943856
通过上述结果可以得出:
对于不可变类型,不存在真正的“拷贝”概念,无论采用赋值、浅拷贝还是深拷贝,其内存ID地址始终相同。
接下来看针对可变对象(如列表)的深浅拷贝示例。
import copy
test=[1,2,3]
print("=====赋值=====")
b=test
print(test)
print(b)
print(id(test))
print(id(b))
print("=====浅拷贝=====")
b=copy.copy(test)
print(test)
print(b)
print(id(test))
print(id(b))
print("=====深拷贝=====")
b=copy.deepcopy(test)
print(test)
print(b)
print(id(test))
print(id(b))
运行结果如下: =====赋值===== [1, 2, 3] [1, 2, 3] 2461497814592 2461497814592 =====浅拷贝===== [1, 2, 3] [1, 2, 3] 2461497814592 2461497661824 =====深拷贝===== [1, 2, 3] [1, 2, 3] 2461497814592 2461497661888
import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始对象
b = a #赋值,传对象的引用
c = copy.copy(a) #对象拷贝,浅拷贝
d = copy.deepcopy(a) #对象拷贝,深拷贝
a.append(5) #修改对象a
a[4].append('c') #修改对象a中的['a', 'b']数组对象
print( 'a = ', a )
print( 'b = ', b )
print( 'c = ', c )
print( 'd = ', d )
此外,对于包含嵌套列表的可变对象,修改原列表后的输出结果如下: ('a = ', [1, 2, 3, 4, ['a', 'b', 'c'], 5]) ('b = ', [1, 2, 3, 4, ['a', 'b', 'c'], 5]) ('c = ', [1, 2, 3, 4, ['a', 'b', 'c']]) ('d = ', [1, 2, 3, 4, ['a', 'b']])
从结果可以总结出三条规律: 1. 当对外层列表添加元素时,浅拷贝后的列表不会随原列表变化;但若修改内层嵌套列表,浅拷贝后的列表也会随之变化。 2. 无论源列表如何变化,深拷贝后的列表始终保持不变。 3. 赋值操作得到的对象会随原列表一起变化。
总结上述规律: 1. 外层添加元素时,浅拷贝不会随原列表变化;内层添加元素时,浅拷贝才会随之变化。 2. 无论源列表如何变化,深拷贝都保持不变。 3. 赋值复制的对象会随原列表一起变化。
综上所述: 1. 外层添加元素时,浅拷贝不会随原列表变化;内层添加元素时浅拷贝才会变化。 2. 无论源列表如何变化,深拷贝都保持不变。 3. 复制对象随原列表一起变化。
总结
本文到此结束,希望这些解析能帮助你更好地理解Python中的内存管理机制。欢迎持续关注本站以获取更多技术内容!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









