从内存分析Python3中的深浅拷贝和赋值的区别

从内存分析Python3中的深浅拷贝和赋值的区别

内容概要

操作内存分析变更效果详细说明
赋值
(=)
两个变量指向同一内存地址。对变量所指向内存地址的内容做任何变动,另一变量均与其发生一样的变化。除非变量所指向的内存地址发生变化(即重新赋值),否则两个变量可以视为同一个。
浅拷贝
(copy)
两个变量指向不同内存地址;
两个变量存储的内容中,无论是变量还是常量,指向的内存地址或分配的内存地址均一致。
如果更换首层元素中的子变量,变更内容仅在自身发生;
如果对首层元素中的子变量所存储的内容进行变更,拷贝与被拷贝的变量均发生变更;
如果对首层元素中的常量进行变更,变更内容仅在自身发生。
通过浅拷贝将原变量指向的内容拷贝出一份,放到新的内存空间中。
更换子变量:直接变更变量中指向的地址,即指向新子变量的地址,所以拷贝出来的变量不受影响;
子变量内容变更:由于拷贝与被拷贝的变量指向的子变量地址相同,其指向的子变量内容发生变更时,两者均会发生相同的变更;
常量变更:变更常量实质是变更指向的地址,故仅在变量自身中发生变动,拷贝出的变量不受影响。
深拷贝
(deepcopy)
两个变量指向不同内存地址;
两个变量存储的内容中,如果是常量则存储的地址一致,如果是变量则指向的地址不同。
任一变量发生任何变动,另一变量均不受影响。通过深拷贝,逐层将变量中的内容均拷贝出来放在新的内存空间,故所有层次的变量指向的地址均与原变量不同,故对变量所指向内容的变动不影响深拷贝出的变量;
在双方变量中引用的常量存储在同一内容地址中,但由于常量变更即是变更了指向对象,也是属于变量内容的变更,而常量本身没有发生变化,因此也不会互相影响。

代码分析

1. 静态比较

通过对内存地址或指向地址的分析,了解深浅拷贝与赋值操作是如何影响变量的:

通过各种方式使变量获取相同的内容
a = [[3], 1, 2]
b = a.copy()
c = copy.deepcopy(a)
d = a

查看各变量所指向的内存地址, 通过拷贝获取内容的变量,其指向的内存地址与原变量所指向的不同
a: 38108400;
b: 38108792;
c: 38108512;
d: 38108400.

比较存储的变量所指向的内存地址, 通过深拷贝获取的子变量,其所指向的内存地址也不同
浅拷贝:a: 38108736, b: 38108736
深拷贝:a: 38108736, c: 38108568
赋值:a: 38108736, d: 38108736

比较存储的常量所分配的内存地址, 所有常量的存储地址均相同
浅拷贝:a: 8791402687248, b: 8791402687248
深拷贝:a: 8791402687248, c: 8791402687248
赋值:a: 8791402687248, d: 8791402687248

参考代码如下:

import copy

a = [[3], 1, 2]
b = a.copy()
c = copy.deepcopy(a)
d = a

print('通过各种方式使变量获取相同的内容')
print('a: {aa};\nb: {bb};\nc: {cc};\nd: {dd}.'.format(**{'aa': a, 'bb': b, 'cc': c, 'dd': d}))

print('查看各变量所指向的内存地址')
print('a: {aa};\nb: {bb};\nc: {cc};\nd: {dd}.'.format(**{'aa': id(a), 'bb': id(b), 'cc': id(c), 'dd': id(d)}))

print('比较存储的变量所指向的内存地址')
print('浅拷贝:a: %s,    b: %s' % (id(a[0]), id(b[0])))
print('深拷贝:a: %s,    c: %s' % (id(a[0]), id(c[0])))
print('赋值:a: %s,    d: %s' % (id(a[0]), id(d[0])))
print('比较存储的常量所分配的内存地址')
print('浅拷贝:a: %s,    b: %s' % (id(a[1]), id(b[1])))
print('深拷贝:a: %s,    c: %s' % (id(a[1]), id(c[1])))
print('赋值:a: %s,    d: %s' % (id(a[1]), id(d[1])))

2. 动态比较

通过对变量和常量进行变更,了解深浅拷贝与赋值操作是如何影响变量的:

变更所存储的变量, 仅通过“赋值操作”获得的变量会随原变量一起变更。
原内容: [[3], 1, 2]
执行动作:替换原列表,a[0] = [9, 9]
变更后:
浅拷贝:a: [[9, 9], 1, 2], b: [[3], 1, 2]
深拷贝:a: [[9, 9], 1, 2], c: [[3], 1, 2]
赋值:a: [[9, 9], 1, 2], d: [[9, 9], 1, 2]

变更子变量的内容, 通过“浅拷贝”、“赋值操作”获得的变量均会随原变量一起变更,深拷贝获得的变量不受影响。
原内容: [[3], 1, 2]
执行动作:增加原列表内容,a[0].append(4)
变更后:
浅拷贝:a: [[3, 4], 1, 2], b: [[3, 4], 1, 2]
深拷贝:a: [[3, 4], 1, 2], c: [[3], 1, 2]
赋值:a: [[3, 4], 1, 2], d: [[3, 4], 1, 2]

变更所存储常量的内容, 仅通过“赋值操作”获得变量会随原变量一起变更。
原内容: [[3], 1, 2]
执行动作:替换原常量,a[1] = 0
变更后:
浅拷贝:a: [[3], 0, 2], b: [[3], 1, 2]
深拷贝:a: [[3], 0, 2], c: [[3], 1, 2]
赋值:a: [[3], 0, 2], d: [[3], 0, 2]

参考代码如下:

import copy

print('变更所存储的变量')
a = [[3], 1, 2]
b = a.copy()
c = copy.deepcopy(a)
d = a
print('原内容:', a)
a[0] = [9, 9]
print('变更后:')
print('浅拷贝:a: %s,    b: %s' % (a, b))
print('深拷贝:a: %s,    c: %s' % (a, c))
print('赋值:a: %s,    d: %s' % (a, d))

print('变更子变量的内容')
a = [[3], 1, 2]
b = a.copy()
c = copy.deepcopy(a)
d = a
print('原内容:', a)
a[0].append(4)
print('变更后:')
print('浅拷贝:a: %s,    b: %s' % (a, b))
print('深拷贝:a: %s,    c: %s' % (a, c))
print('赋值:a: %s,    d: %s' % (a, d))

print('变更所存储常量的内容')
a = [[3], 1, 2]
b = a.copy()
c = copy.deepcopy(a)
d = a
print('原内容:', a)
a[1] = 0
print('变更后:')
print('浅拷贝:a: %s,    b: %s' % (a, b))
print('深拷贝:a: %s,    c: %s' % (a, c))
print('赋值:a: %s,    d: %s' % (a, d))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值