Python赋值、浅拷贝与深拷贝机制详解

Hazel
Hazel
发布时间:2026-10-16 | 2人浏览过
原创

本文详细解析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中的内存管理机制。欢迎持续关注本站以获取更多技术内容!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表