python list的深复制与浅复制思考

本文探讨了Python中深浅复制的概念,通过具体代码示例解析了列表和其他数据类型在不同复制方式下的行为差异。文章深入分析了栈和堆在Python内存管理中的角色,解释了为何某些数据类型适合栈存储而另一些则更适合堆存储。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先看一段源码

a = [['_']*3 for i in range(3)]
a[1][2] = 1
print(a)

b = [['_']*3]*3
b[1][2] = 1
print(b)

c = []
for i in range(3):
    row = ['_']*3
    c.append(row)
c[1][2] = 1
print(c)

d = []
row = ['_']*3
for i in range(3):
    d.append(row)
d[1][2] = 1
print(d)
[['_', '_', '_'], ['_', '_', 1], ['_', '_', '_']]
[['_', '_', 1], ['_', '_', 1], ['_', '_', 1]]
[['_', '_', '_'], ['_', '_', 1], ['_', '_', '_']]
[['_', '_', 1], ['_', '_', 1], ['_', '_', 1]]

这里涉及到了深复制和浅复制的区别,需要弄清楚栈和堆的区分, 因为栈与堆的运行速度是数量级差异,而且栈还有可能把数据直接调入寄存器进行读写,又因栈内空间十分有限,所以有了深复制与浅复制,默认浅复制. <深入理解计算机系统> 后有详细的栈堆实现,我目前还是没有看到,但第一章可以有大概的描述.

在这里插入图片描述

再看下面的代码,则可以推论出 * 的重载运算符, append 都是浅复制, 包括list的实现也是指针的集合. list我的现阶段的理解是, 指向堆内数据指针的集合, 而且因为把这些指针的地址排列成连续的内存结构, 所以可以用索引访问. 因为c++的 链表 二叉树因为内存不连续,所以无法用索引访问, 由此推出以上结论.

a = [['_']*3 for i in range(3)]
a[1][2] = 1
print(a)

b = [['_']*3]*3
b[1][2] = 1
print(b)
for i in range(3):
    for j in range(3):
        print(id(b[i][j]))

c = []
for i in range(3):
    row = ['_']*3
    c.append(row)
c[1][2] = 1
print(c)


d = []
row = ['_']*3
for i in range(3):
    d.append(row)
print(d)
d[1][2] = 1
print(d[0][0] is d[0][1])
print(id(row))
for i in range(3):
    for j in range(3):
        print(id(d[i][j]))

[['_', '_', '_'], ['_', '_', 1], ['_', '_', '_']]
[['_', '_', 1], ['_', '_', 1], ['_', '_', 1]]
2171792199896
2171792199896
1609591840
2171792199896
2171792199896
1609591840
2171792199896
2171792199896
1609591840
[['_', '_', '_'], ['_', '_', 1], ['_', '_', '_']]
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
True
2171797620552
2171792199896
2171792199896
1609591840
2171792199896
2171792199896
1609591840
2171792199896
2171792199896
1609591840

相同的内存地址,说明了其是堆区的内存地址,但是栈区的指针地址不知道用什么方法可以访问到,可能是因为栈区 读写太快,不便取址的原因没有设计还是什么原因, 需要日后解决.
可以确定是,python设计中,绝大部分都应该是以浅复制以及赋值为主, 比如int , float 类型数据,因为读写占用资源并不多, 若以引用的形式进行操作, 性价比并不高, 或许寻址花费的时间还要超过运算时间, 所以 此类数据一般都为 对其值进行操作,而且可以让其在栈内 甚至是在寄存器内读写(记得c/c++ 都有强制在寄存器读写的作用域命令关键字). 而对于list 以及大型数据类型, 就是需要用地址进行操作, 可能是因为性价比高, 寻址花费时间远远低于其直接读写时间, 所以需要在堆内进行读写.
对于衍生出的疑惑:

  1. CPU内有寄存器 L1 或许 还有外围的内存 以至于硬盘作为其上一级高速缓存的一级缓存, 那么堆栈是否有物理上的差异,还是仅仅是虚拟上的差异, 譬如栈总是在高一级缓存实现.
  2. 读写是通过总线进行的, 那么如同知乎上说的 命中率问题的根源是什么. 栈的高效率 到底是由于物理的差异,还是所谓的命中率原因.
  3. 对于指针本身在栈区的地址的获取方法是什么.
    看完<深入理解计算机系统> 再回来续写
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值