深浅拷贝

普通赋值

复制代码
 1 # 1 普通赋值
 2 a = [1, 2, 3]
 3 b = [11, 22, 33]
 4 c = [a, b]
 5 
 6 d = c
 7 
 8 print(id(d))  # 2517490235456
 9 print(id(c))  # 2517490235456
10 print(f"c={c}")  # c=[[1, 2, 3], [11, 22, 33]]
11 print(f"d={d}")  # d=[[1, 2, 3], [11, 22, 33]]
12 print(id(c[1]))  # 1234100025024
13 print(id(d[1]))  # 1234100025024
14 
15 '''
16 普通的赋值就是引用的拷贝。就像windows快捷键一样,本质上指向的同一个东东
17 '''
复制代码

 

浅拷贝(shallow copy)

浅拷贝可变类型

复制代码
 1 import copy  # 1. 导入copy模块
 2 # 2 浅拷贝可变类型
 3 a = [1, 2, 3]
 4 b = [11, 22, 33]
 5 c = [a, b]
 6 
 7 d = copy.copy(c)  # 2. 进行浅拷贝
 8 
 9 print(id(d))  # 2260319076224
10 print(id(c))  # 2493865459584
11 
12 '''
13 浅拷贝就是可变类型操作,就是创建开辟一个新空间,存储拷贝对象
14 '''
复制代码

 

浅拷贝深层可变类型

 

复制代码
 1 import copy  # 1. 导入浅拷贝模块
 2 
 3 #  浅拷贝-可变类型-深层数据
 4 a = [1, 2, 3]
 5 b = [11, 22, 33]
 6 c = [a, b]
 7 
 8 d = copy.copy(c)  # 2. 对深层数据-可变类型进行浅拷贝
 9 
10 #  都是执行a列表
11 print(id(a))     # 1890180887936
12 print(id(c[0]))  # 1890180887936
13 print(id(d[0]))  # 1890180887936
复制代码

说明前拷贝对可变类型拷贝,只拷贝了一层。

浅拷贝不可变类型

复制代码
 1 import copy
 2 
 3 # 浅拷贝不可变类型
 4 a = (1, 2, 3)
 5 b = (11, 22, 33)
 6 c = (a, b)
 7 
 8 d = copy.copy(c)
 9 
10 print(id(d))  # 1565409147712
11 print(id(c))  # 1565409147712
12 '''
13 对不可变类型进行浅拷贝,只是拷贝了引用
14 '''
复制代码

深拷贝(deep copy)

深拷贝可变类型

复制代码
 1 import copy
 2 
 3 # 深拷贝可变类型
 4 a = [1, 2, 3]
 5 b = [11, 22, 33]
 6 c = [a, b]
 7 
 8 d = copy.deepcopy(c)
 9 
10 print(id(c))  # 2384833019136
11 print(id(d))  # 2384833019776
12 
13 print(id(c[0]))  # 2384832984448
14 print(id(d[0]))  # 2384833043264
15 
16 '''
17 对可变类型的每一层可变类型都拷贝了一份
18 '''
复制代码

深拷贝-深层数据的可变类型

复制代码
 1 import copy
 2 
 3 # 深拷贝-深层数据
 4 a = [1, 2, 3]
 5 b = [11, 22, 33]
 6 c = [a, b]  # 此处是拷贝了引用
 7 
 8 d = copy.deepcopy(c)
 9 
10 print(id(a))          # 1490657047936
11 print(id(c[0]))      # 1490657047936
12 print(id(d[0]))     # 1490657106752 变化了
复制代码

深拷贝-拷贝不可变类型

复制代码
 1 import copy
 2 
 3 # 深拷贝不可变类型
 4 a = (1, 2, 3)
 5 b = (11, 22, 33)
 6 c = (a, b)
 7 
 8 d = copy.deepcopy(c)
 9 
10 print(id(c))  # 2367734086464
11 print(id(d))  # 2367734086464
12 
13 '''
14 深拷贝对不可变类型只是拷贝引用
15 '''
复制代码

 

总结

 

 

1
2
3
4
5
6
7
8
9
1. 思考下面的代码运行出的结果是什么:
    list = [0, 1, 2]
    list[1] = list
    print(list)
     
     
参考答案:
    [0, [...], 2]
    list的第2个元素指向list本身, 因此打印时,就无限循环。[0, [...], 2] 中[...]循环引用,指示列表中的某个位置引用了它自己,而不是无限递归地展开整个结构导致内存耗尽。2. 如何得出list = [0, [0, 1, 2], 2]这样的结果? <br>   参考答案: list[1] = list[:] 列表的切片其实是浅拷贝 <br><br>3. 经过以下步骤, a和b分别是多少? 为什么? <br>  a = [0, [12], 3] <br>  b = a[:] <br>  a[0= 8 <br>  a[1][1= 9 <br>  参考答案: a = [8, [1, 9], 3] <br>           b = [0, [1, 9], 3] <br> a[:]是浅拷贝, 只对对象最顶层进行拷贝 <br><br>4. 如何保证第3题中最终b = [0, [12], 3] <br>  参考答案: 使用深拷贝 <br><br>5. 写出下面代码执行结果: <br>   L = [12] <br>   M = L <br>   L = + [34] <br>   print(L) <br>   print(M)<br>输出结果:6. 写出下面代码执行结果: <br>  L = [12] <br>  M = L <br>  L += [34] <br>  print(L) <br>  print(M) <br>输出结果: 说明: <br>  1. L += [3, 4]是L本身加上[3, 4] 等效于 L.extend([3, 4]),即将 [3, 4] 添加到列表 L 中。由于列表是可变对象,这个操作会在现有的列表上进行修改,而不是创建一个新列表。因此,L 现在包含元素 [1, 2, 3, 4]。<br>  2. 而L = L + [3, 4] 先计算等号右边, 得到一个新的引用, 指向新的L(等号右边的L是原来的L, 等号左边的是一个新的L) 练习6<br><br>7. 执行以下代码: def foo(a, b, c=[]):<br>    c.append(a)<br>    c.append(b)<br>    print(c)<br><br><br>foo(1, 2# [1, 2]  python解释器没有接收到c的参数, 使用默认的空列表(缺省参数)<br>foo(1, 2, [])  # [1, 2]  python解释器接收到新的c的参数, 就是用新的空列表, 此时, 缺省参数的列表已经变为[1, 2]<br>foo(3, 4)  # [1, 2, 3, 4]  python解释器没有接收到c的参数, 继续使用默认的缺省列表, 即[1, 2].append[3, 4]<br>foo(1, 2)  # [1, 2, 3, 4, 1, 2]<br>foo(1, 2, [])  # [1, 2]<br>说明:

  [1, 2, 3, 4]
  [1,2]

  [1, 2, 3, 4]
       [1, 2, 3, 4]  

  1. foo(1, 2):在第一次调用函数 foo 时,没有提供 c 参数,因此默认会使用函数定义中的默认空列表。这是因为默认参数在函数定义时会被创建一次然后在后续的函数调用中会继续使用相同的对象。在这里,当你在第一次调用中修改了默认列表,后续的调用会继续使用这个已经被修改的列表。

  2. foo(1, 2, []):在这次调用中,你提供了一个新的空列表作为 c 的参数,因此这个新的空列表会被使用。这不会影响到默认参数因此在后续调用中默认参数依然是已经被修改的列表

  3. foo(3, 4):这次调用没有提供 c 参数,所以继续使用之前被修改过的默认列表。所以这次的输出为 [1, 2, 3, 4]

  4. foo(1, 2):与第一个调用类似,继续使用之前被修改过的默认列表。因此,输出会是 [1, 2, 3, 4, 1, 2]

  5. foo(1, 2, []):与第二次调用类似,你提供了一个新的空列表作为 c 的参数,所以输出为 [1, 2]

总之,这段代码展示了默认参数在函数定义时只会被创建一次,并在后续的函数调用中持续使用。如果默认参数是可变对象(如列表),它可能会在多次函数调用中累积修改。为了避免这种情况,可以将默认参数设置为不可变对象,如 None,然后在函数内部根据需要创建新的对象。

  

posted @   Allen_Hao  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
点击右上角即可分享
微信分享提示