[Python3 填坑] 009 深拷贝与浅拷贝

阅读: 评论:0

[Python3 填坑] 009 深拷贝与浅拷贝

[Python3 填坑] 009 深拷贝与浅拷贝

目录

  • 1. print( 坑的信息 )
  • 2. 开始填坑
    • 2.1 Python3.7 官方文档
    • 2.2 赋值、切片与 copy()
      • 分析
      • 分析
      • 分析
      • 分析
    • 2.3 copy 模块
      • 分析
      • 分析
    • 2.4 小结
    • 2.5 copy 模块的补充
      • 2.5.1 使用场合
      • 2.5.2 深拷贝的问题与解决
      • 2.5.3 浅拷贝的作用
  • 挖坑时间:2019/01/10
  • 明细
坑的编码内容
Py006-3Python3 中的深拷贝与浅拷贝


2. 开始填坑

2.1 Python3.7 官方文档

  • 文档地址

2.2 赋值、切片与 copy()

# 例 1
lst1_1 = [0, 1, 2, 3, 4]
lst1_2 = lst1_1         # Python 的赋值语句不复制对象,而是在目标和对象之间建立联系
lst1_3 = lst1_1[:]      # 切片
lst1_4 = py()  # copy()print("lst1_1 =", lst1_1)
print("lst1_2 =", lst1_2)
print("lst1_3 =", lst1_3)
print("lst1_4 =", lst1_4)
print('-'*30)print("id(lst1_1) =", id(lst1_1))
print("id(lst1_2) =", id(lst1_2))
print("id(lst1_3) =", id(lst1_3))
print("id(lst1_4) =", id(lst1_4))

>>>

lst1_1 = [0, 1, 2, 3, 4]
lst1_2 = [0, 1, 2, 3, 4]
lst1_3 = [0, 1, 2, 3, 4]
lst1_4 = [0, 1, 2, 3, 4]
------------------------------
id(lst1_1) = 2523757320136
id(lst1_2) = 2523757320136
id(lst1_3) = 2523757319624
id(lst1_4) = 2523757319816

分析

  • lst1_1 与 lst1_2 指向同一片内存地址,是同一事物的两个名字
  • 切片与 copy() 开辟了新的空间,产生的是新事物


# 例 2
lst2_1 = [111, 222, 333, 444]
lst2_2 = lst2_1
lst2_3 = lst2_1[:]
lst2_4 = py()lst2_1[0] = 'a'
print("lst2_1 =", lst2_1)
print("lst2_2 =", lst2_2)
print("lst2_3 =", lst2_3)
print("lst2_4 =", lst2_4)
print('-'*30)lst2_2[1] = 'b'
print("lst2_1 =", lst2_1)
print("lst2_2 =", lst2_2)
print("lst2_3 =", lst2_3)
print("lst2_4 =", lst2_4)
print('-'*30)lst2_3[2] = 'c'
print("lst2_1 =", lst2_1)
print("lst2_2 =", lst2_2)
print("lst2_3 =", lst2_3)
print("lst2_4 =", lst2_4)
print('-'*30)lst2_4[3] = 'd'
print("lst2_1 =", lst2_1)
print("lst2_2 =", lst2_2)
print("lst2_3 =", lst2_3)
print("lst2_4 =", lst2_4)

>>>

lst2_1 = ['a', 222, 333, 444]
lst2_2 = ['a', 222, 333, 444]
lst2_3 = [111, 222, 333, 444]
lst2_4 = [111, 222, 333, 444]
------------------------------
lst2_1 = ['a', 'b', 333, 444]
lst2_2 = ['a', 'b', 333, 444]
lst2_3 = [111, 222, 333, 444]
lst2_4 = [111, 222, 333, 444]
------------------------------
lst2_1 = ['a', 'b', 333, 444]
lst2_2 = ['a', 'b', 333, 444]
lst2_3 = [111, 222, 'c', 444]
lst2_4 = [111, 222, 333, 444]
------------------------------
lst2_1 = ['a', 'b', 333, 444]
lst2_2 = ['a', 'b', 333, 444]
lst2_3 = [111, 222, 'c', 444]
lst2_4 = [111, 222, 333, 'd']

分析

  • 结合例 1,可以看出,对整个列表(一个完整对象)而言
    • 指向同一片地址的事物是“有难同当”的
    • 指向不同地址的事物是“井水不犯河水”的


# 例 3
lst3_1 = [0, 1, 2, [3, 4, 5]]
lst3_2 = lst3_1
lst3_3 = lst3_1[:]
lst3_4 = py()print("id(lst3_1[0]) =", id(lst3_1[0]))
print("id(lst3_2[0]) =", id(lst3_2[0]))
print("id(lst3_3[0]) =", id(lst3_3[0]))
print("id(lst3_4[0]) =", id(lst3_4[0]))
print('-'*30)print("id(lst3_1[3]) =", id(lst3_1[3]))
print("id(lst3_2[3]) =", id(lst3_2[3]))
print("id(lst3_3[3]) =", id(lst3_3[3]))
print("id(lst3_4[3]) =", id(lst3_4[3]))
print('-'*30)print("id(lst3_1[3][0]) =", id(lst3_1[3][0]))
print("id(lst3_2[3][0]) =", id(lst3_2[3][0]))
print("id(lst3_3[3][0]) =", id(lst3_3[3][0]))
print("id(lst3_4[3][0]) =", id(lst3_4[3][0]))

>>>

id(lst3_1[0]) = 140733084593888
id(lst3_2[0]) = 140733084593888
id(lst3_3[0]) = 140733084593888
id(lst3_4[0]) = 140733084593888
------------------------------
id(lst3_1[3]) = 2523758754824
id(lst3_2[3]) = 2523758754824
id(lst3_3[3]) = 2523758754824
id(lst3_4[3]) = 2523758754824
------------------------------
id(lst3_1[3][0]) = 140733084593984
id(lst3_2[3][0]) = 140733084593984
id(lst3_3[3][0]) = 140733084593984
id(lst3_4[3][0]) = 140733084593984

分析

  • 这些列表内部,无论“第一层”还是“第二层”,对应元素的地址其实是相同的


# 例 4
lst4_1 = [0, 1, 2, [30, 31, 32]]
lst4_2 = lst4_1
lst4_3 = lst4_1[:]
lst4_4 = py()lst4_1[3].append(33)
print("lst4_1 =", lst4_1)
print("lst4_2 =", lst4_2)
print("lst4_3 =", lst4_3)
print("lst4_4 =", lst4_4)
print('-'*40)lst4_3[3][0] = 66
print("lst4_1 =", lst4_1)
print("lst4_2 =", lst4_2)
print("lst4_3 =", lst4_3)
print("lst4_4 =", lst4_4)
print('-'*40)lst4_4[3][1] = 888
print("lst4_1 =", lst4_1)
print("lst4_2 =", lst4_2)
print("lst4_3 =", lst4_3)
print("lst4_4 =", lst4_4)

>>>

lst4_1 = [0, 1, 2, [30, 31, 32, 33]]
lst4_2 = [0, 1, 2, [30, 31, 32, 33]]
lst4_3 = [0, 1, 2, [30, 31, 32, 33]]
lst4_4 = [0, 1, 2, [30, 31, 32, 33]]
----------------------------------------
lst4_1 = [0, 1, 2, [66, 31, 32, 33]]
lst4_2 = [0, 1, 2, [66, 31, 32, 33]]
lst4_3 = [0, 1, 2, [66, 31, 32, 33]]
lst4_4 = [0, 1, 2, [66, 31, 32, 33]]
----------------------------------------
lst4_1 = [0, 1, 2, [66, 888, 32, 33]]
lst4_2 = [0, 1, 2, [66, 888, 32, 33]]
lst4_3 = [0, 1, 2, [66, 888, 32, 33]]
lst4_4 = [0, 1, 2, [66, 888, 32, 33]]

分析

  • 像例 4 这样列表中嵌套的列表(第二层),赋值、切片、copy() 都是“有难同当”的


2.3 copy 模块

# 例 5
import copy                     # 导入 copy 模块lst5_1 = [0, 1, 2, [30, 31]]
lst5_2 = py(lst5_1)      # 浅拷贝
lst5_3 = copy.deepcopy(lst5_1)  # 深拷贝print("lst5_1 =", lst5_1)
print("lst5_2 =", lst5_2)
print("lst5_3 =", lst5_3)
print('-'*40)print("id(lst5_1) =", id(lst5_1))
print("id(lst5_2) =", id(lst5_2))
print("id(lst5_3) =", id(lst5_3))
print('-'*40)lst5_1.append(4)
print("lst5_1 =", lst5_1)
print("lst5_2 =", lst5_2)
print("lst5_3 =", lst5_3)
print('-'*40)lst5_1[3].append(32)
print("lst5_1 =", lst5_1)
print("lst5_2 =", lst5_2)
print("lst5_3 =", lst5_3)

>>>

lst5_1 = [0, 1, 2, [30, 31]]
lst5_2 = [0, 1, 2, [30, 31]]
lst5_3 = [0, 1, 2, [30, 31]]
----------------------------------------
id(lst5_1) = 2523758966408
id(lst5_2) = 2523758966280
id(lst5_3) = 2523758881096
----------------------------------------
lst5_1 = [0, 1, 2, [30, 31], 4]
lst5_2 = [0, 1, 2, [30, 31]]
lst5_3 = [0, 1, 2, [30, 31]]
----------------------------------------
lst5_1 = [0, 1, 2, [30, 31, 32], 4]
lst5_2 = [0, 1, 2, [30, 31, 32]]
lst5_3 = [0, 1, 2, [30, 31]]

分析

  • 深、浅拷贝均与赋值不同
  • 切片、copy() 可以看作浅拷贝
  • 浅拷贝顶得住“第一层”却顶不住“第二层”
  • 深拷贝的“第二层”也“不容侵犯”


# 例 6
import copy                     # 导入 copy 模块lst6_1 = {'a':"apple", 'b':["banana"], 'c':["carambola", "cherry", "coconut"]}
lst6_2 = py(lst6_1)      # 浅拷贝
lst6_3 = copy.deepcopy(lst6_1)  # 深拷贝print("id(lst6_1) =", id(lst6_1))
print("id(lst6_2) =", id(lst6_2))
print("id(lst6_3) =", id(lst6_3))
print('-'*40)print("id(lst6_1['a']) =", id(lst6_1['a']))
print("id(lst6_2['a']) =", id(lst6_2['a']))
print("id(lst6_3['a']) =", id(lst6_3['a']))
print('-'*40)print("id(lst6_1['b']) =", id(lst6_1['b']))
print("id(lst6_2['b']) =", id(lst6_2['b']))
print("id(lst6_3['b']) =", id(lst6_3['b']))
print('-'*40)print("id(lst6_1['c']) =", id(lst6_1['c']))
print("id(lst6_2['c']) =", id(lst6_2['c']))
print("id(lst6_3['c']) =", id(lst6_3['c']))
print('-'*40)lst6_1['a'] = "arbutus"
print("lst6_1['a'] =", lst6_1['a'])
print("lst6_2['a'] =", lst6_2['a'])
print("lst6_3['a'] =", lst6_3['a'])
print('-'*40)lst6_1['b'].append("berry")
print("lst6_1['b'] =", lst6_1['b'])
print("lst6_2['b'] =", lst6_2['b'])
print("lst6_3['b'] =", lst6_3['b'])
print('-'*40)lst6_1['c'].remove("cherry")
print("lst6_1['c'] =", lst6_1['c'])
print("lst6_2['c'] =", lst6_2['c'])
print("lst6_3['c'] =", lst6_3['c'])

>>>

id(lst6_1) = 2298694416712
id(lst6_2) = 2298694594848
id(lst6_3) = 2298694594920
----------------------------------------
id(lst6_1['a']) = 2298693712952
id(lst6_2['a']) = 2298693712952
id(lst6_3['a']) = 2298693712952
----------------------------------------
id(lst6_1['b']) = 2298694533576
id(lst6_2['b']) = 2298694533576
id(lst6_3['b']) = 2298694533768
----------------------------------------
id(lst6_1['c']) = 2298694533704
id(lst6_2['c']) = 2298694533704
id(lst6_3['c']) = 2298694533640
----------------------------------------
lst6_1['a'] = arbutus
lst6_2['a'] = apple
lst6_3['a'] = apple
----------------------------------------
lst6_1['b'] = ['banana', 'berry']
lst6_2['b'] = ['banana', 'berry']
lst6_3['b'] = ['banana']
----------------------------------------
lst6_1['c'] = ['carambola', 'coconut']
lst6_2['c'] = ['carambola', 'coconut']
lst6_3['c'] = ['carambola', 'cherry', 'coconut']

分析

  • 字典与列表稍有不同
  • 若字典的值是列表,则该列表属于“第二层”


2.4 小结

  • 深拷贝,拷贝的是原对象内部的元素,是一个真正的副本
  • 浅拷贝,拷贝的是原对象内部数据的地址,并不是一个真正的副本

    • 拷贝后的新对象占用新的空间,但其内部的元素指向原对象内部对应元素的地址
    • “顶层拷贝”之称,即不变动拷贝后新对象的第一层元素
    • 当原对象中非第一层的可变元素发生变化时,新对象中的对应元素同步变化

2.5 copy 模块的补充

2.5.1 使用场合

  • copy 模块常用于复合对象
    • 复合对象:包含其他对象的对象,如列表、类实例等
  • 它不能拷贝模块、方法、堆栈跟踪、堆栈帧、文件、套接字、窗口、数组等
  • 必要时,可以重写 py(x) 和 copy.deepcopy(x[, memo])

2.5.2 深拷贝的问题与解决

问题
  1. 递归对象(直接或间接包含对自身引用的复合对象)可能导致递归循环
  2. 因为深拷贝会复制原对象的一切,所以可能复制过多的内容;例如,打算在副本之间共享的数据
解决方法
  1. 保存在当前复制过程中已经复制的对象的 memo 字典
  2. 让用户定义的类重写复制操作或复制的组件集

2.5.3 浅拷贝的作用

  1. 提前做浅拷贝可以防止后期因变量名众多而产生混乱
  2. 可应用于“联合账号”等

倘若阁下发现在下错误之处,还请不吝赐教!谢谢!

转载于:.html

本文发布于:2024-01-29 01:11:20,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170646188511640.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23