鱼C论坛

 找回密码
 立即注册
查看: 560|回复: 1

[经验总结] Python 可变/不可变/浅拷贝

[复制链接]
发表于 2023-8-30 16:10:35 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 Free_num 于 2023-8-30 16:19 编辑

可变/不可变/浅拷贝
'''
<font size="3" color="#ff8c00">可变类型</font>:数据可直接进行修改且id不变化---------->证明修改的是原值
<font color="#ff8c00" size="3">不可变类型</font>:值改变,id也变---------->原值不能被修改

二者可以通过ID来区分
可变类型:列表、字典、集合
不可变类型:字符串、元组、数据类型

元组被称为制度列表,即数据可以被查询,但是不能被修改,
'''

'''
li = [1, 2]
t = (1, 't', li)
print(f'修改元组中的列表前:{t}', id(t))
# 修改元组中的列表前:(1, 't', [1, 2]) 1931246079296
li[0] = 'Serena'
print(f'修改元组中的列表后:{t}', id(t))
# 修改元组中的列表后:(1, 't', ['Serena', 2]) 1931246079296


上面结果中,虽然元组数据发生了变化,但是id却未发生变化,那是因为元组中的列表是可变类型,列表的数据发生了变化,
但列表在元组中的地址的值没有发生变化
因此,元组的地址没有发生变化
'''



'''
<font size="3" color="#ff8c00">赋值:</font>如果是  <u><i>可变类型数据</i></u>,赋值对象随着源对象的改变而改变,二者指向的是同一个内存地址
           如果是  <u><i>不可变类型数据</i></u>,没有影响
'''
<span style="background-color: mediumturquoise;"># 可变类型数据</span>
li1 = [1, 3, 5, [3]]
li2 = li1
print(f'源列表修改前li1:{li1}', id(li1))
print(f'源列表修改前li2:{li2}', id(li2))

li1[3][0] = 's'
print(f'源列表修改后li1:{li1}', id(li1))
print(f'源列表修改后li2:{li2}', id(li2))

li2[3][0] = 123
print(f'li2列表修改后li1:{li1}', id(li1))
print(f'li2列表修改后li2:{li2}', id(li2))
'''
以上的id值均相同----->赋值是可变类型数据,内存地址是同一个,所以无论改变的是源对象还是赋值对象,id都一样
'''

<span style="background-color: mediumturquoise;"># 不可变类型数据</span>
a = 7
b = a
print(id(a),'\t', id(b))    # 2023961330096          2023961330096
# 对源对象进行修改
a = 's'
print(id(a), '\t', id(b))   # 2023962151920          2023961330096 ------> 没有影响

 

<span style="background-color: mediumturquoise;"><font size="4"># 深、浅拷贝,使用时需要导包 import copy</font></span>
'''
<font size="3" color="#ff8c00"> 浅拷贝:</font>创建一个新对象,引用的是源对象的子对象---------内层地址不会改变,外层数据地址改不改变看外层数据类型
使用:copy.copy()
'''
import copy
<span style="background-color: mediumturquoise;"><font size="3"># 外层可变,内层可变</font></span>
l = [1, 3, 5, {'q', 'o^0'}]
l1 = copy.copy(l)
print('源对象外层数据地址:', l, id(l))                                      # 1589324513344
print('浅拷贝后的外层数据地址:', l1, id(l1))                           # 1589324494400  外层地址改变
print('--------- 内层 ----------')
print('源对象内层数据地址:', id(l[3]))                                 # 1589324258144
print('浅拷贝后的内层数据地址:', id(l[3]))                         #  1589324258144  内层地址不变
print('-------------------')
l.append('¥')
print('外层修改后源对象:', l)                                      # [1, 3, 5, {'o^0', 'q'}, '¥']
print('外层修改后的浅拷贝:', l1)                                 # [1, 3, 5, {'o^0', 'q'}]
print('-------------------')                                               # 外层内存地址不同,数据不会产生影响,外层数据是独立的
l[3].remove('q')
print('内层数据修改后源对象:', l)                              # [1, 3, 5, {'o^0'}, '¥']
print('内层数据修改后的浅拷贝:', l1)                         # [1, 3, 5, {'o^0'}]
print('-------------------')
<span style="background-color: wheat;">'''
引用的是源对象的子对象,所以内层内存地址相同,
由于内层是可变类型,可变类型数据发生变化时,id不变,因此当内层数据发生变化时,用的还是原来的内存地址,
故当内层发生变化时,浅拷贝对象的内层也发生相同的变化
'''</span>

<span style="background-color: mediumturquoise;"><font size="3"># 外层可变,内层不可变</font></span>
l2 = [2, 3, ('s', 'r')]
l3 = copy.copy(l2)
print('源对象外层数据地址', l2, id(l2))                                  # [2, 3, ('s', 'r')] 1589324494144
print('浅拷贝后的外层数据地址:', l3, id(l3))                        # [2, 3, ('s', 'r')] 1589324495104  外层地址改变
print('--------- 内层 ----------')
print('源对象内层数据地址:', id(l2[2]))                              # 1589322737344
print('浅拷贝后的内层数据地址:', id(l2[2]))                       # 1589322737344     内层地址不变
print('-------------------')
l2.insert(1, 'e')
print('外层修改后源对象:', l2)                                          # [2, 'e', 3, ('s', 'r')]
print('外层修改后的浅拷贝:', l3)                                      # [2, 3, ('s', 'r')]       原因同上,外层数据资源独立
print('-------------------')
l2[-1] += (60,)
print('内层数据修改后源对象:', l2)                                 # [2, 'e', 3, ('s', 'r', 60)]
print('内层数据修改后的浅拷贝:', l3)                              # [2, 3, ('s', 'r')]
print('-------------------')
<span style="background-color: wheat;">'''
引用的是源对象的子对象,所以内层内存地址相同,
由于内层数据是不可变类型,当内层数据发生变化时,id发生变化,
而浅拷贝引用的是改变之前的内存空间,
故当内存数据发生改变时,浅拷贝的对象未发生变化
'''</span>


<span style="background-color: mediumturquoise;"><font size="3"># 外层不可变,内层可变</font></span>
l4 = [1, 3, 5]
t = ('er', 4, l4)
t1 = copy.copy(t)
print('源对象外层数据地址', t, id(t))                # 1589324527488
print('浅拷贝后的外层数据地址', t1, id(t1))           # 1589324527488    外层地址未发生变化
print('--------- 内层 ----------')
print('源对象内层数据地址', id(l4))                  # 1589324493440
print('浅拷贝后的内层数据地址', id(t1[-1]))           # 1589324493440    内层地址不变
print('-------------------')
t += (90,)
print('外层数据修改后源对象:', t)             # ('er', 4, [1, 3, 5], 90)
print('外层数据修改后的浅拷贝:', t1)          # ('er', 4, [1, 3, 5])
print('-------------------')
l4.append('WE')
print('内层数据修改后源对象:', t)             # ('er', 4, [1, 3, 5, 'WE'], 90)
print('内层数据修改后的浅拷贝:', t1)           # ('er', 4, [1, 3, 5, 'WE'])

<font size="3" style="background-color: mediumturquoise;"># 外层不可变,内层不可变</font>
'''
这个就先不举例子啦

综上所述:
 浅拷贝内层数据内存地址不会发生改变
 外层数据是可变类型-----会改变
        是不可变类型-----不会改变
'''

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2023-9-8 11:51:18 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-21 19:45

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表