1. print( 坑的信息 )

  • 挖坑时间:2019/01/10
  • 明细
坑的编码 内容
Py006-3 Python3 中的深拷贝与浅拷贝

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 = lst1_1.copy() # 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 = lst2_1.copy() 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 = lst3_1.copy() 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 = lst4_1.copy() 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 = copy.copy(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 = copy.copy(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 模块常用于复合对象

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

2.5.2 深拷贝的问题与解决

问题

  1. 递归对象(直接或间接包含对自身引用的复合对象)可能导致递归循环
  2. 因为深拷贝会复制原对象的一切,所以可能复制过多的内容;例如,打算在副本之间共享的数据

解决方法

  1. 保存在当前复制过程中已经复制的对象的 memo 字典
  2. 让用户定义的类重写复制操作或复制的组件集

2.5.3 浅拷贝的作用

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

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

[Python3 填坑] 009 深拷贝与浅拷贝的更多相关文章

  1. [Python3 填坑] 006 “杠零”,空字符的使用

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 \0 是空字符,输出时看不到它,但它占 1 个字符的长度 2.2 \0 "遇八进制失效" 2.3 \0 与 '' 不 ...

  2. [Python3 填坑] 004 关于八进制

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 问题的由来 2.2 问题的解决 2.2.1 先说结论 2.2.2 八进制的用途 2.2.3 少废话,上例子 1. print( 坑的信息 ...

  3. [Python3 填坑] 001 格式化符号 & 格式化操作符的辅助指令

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 Python 格式化符号表 举例说明 (1) %c (2) %s 与 %d (3) %o (4) %x (5) %f (6) %e (7 ...

  4. [Python3 填坑] 012 字典的遍历在 Python2 与 Python3 中区别

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 Python2 中字典的遍历 2.2 Python3 中字典的遍历 2.3 结论 1. print( 坑的信息 ) 挖坑时间:2019/ ...

  5. [Python3 填坑] 005 如何“响铃”

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 问题的由来 2.2 问题的解决 1. print( 坑的信息 ) 挖坑时间:2019/01/08 明细 坑的编码 内容 Py004-2 ...

  6. [Python3 填坑] 003 关键字?保留字?预留字?

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 问题的由来 2.2 网上搜索 2.3 结论 2.4 后记 1. print( 坑的信息 ) 挖坑时间:2019/01/04 明细 坑的编 ...

  7. [Python3 填坑] 018 组装类的几个例子

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 MetaClass 举例 2.2 type 举例 2.3 MetaClass 举例 1. print( 坑的信息 ) 挖坑时间:2019 ...

  8. [Python3 填坑] 017 实例方法、静态方法、类方法的区别

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 先上例子 2.2 分析 1. print( 坑的信息 ) 挖坑时间:2019/04/07 明细 坑的编码 内容 Py024-1 实例方法 ...

  9. [Python3 填坑] 016 对 __getattr__ 和 __setattr__ 举例

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 __getattr__ 2.2 __setattr__ 1. print( 坑的信息 ) 挖坑时间:2019/04/07 明细 坑的编码 ...

随机推荐

  1. 强化学习(Reinfment Learning) 简介

    本文内容来自以下两个链接: https://morvanzhou.github.io/tutorials/machine-learning/reinforcement-learning/ https: ...

  2. .net core Consul

    创建API项目修改Program public class Program { public static void Main(string[] args) { CreateWebHostBuilde ...

  3. 在国外搭建 Web 服务器 - Linode VPS

    在国外搭建 Web 服务器 - Linode VPS 买一台虚拟服务器(VPS),把你网站放在上面跑跑,找找感觉,平时也可以用它来练习.前几天,搜索到了有人推荐 Linode 的 VPS,昨天又有朋友 ...

  4. HDU-4280-Island Transport(网络流,最大流, ISAP)

    链接: https://vjudge.net/problem/HDU-4280 题意: In the vast waters far far away, there are many islands. ...

  5. python-登录保持

     cookies.Session import requests url1="http://127.0.0.1:5000/login" url2="http://127. ...

  6. Oracle 与 ODAC 一起安装

    Oracle 需要设置path变量支持运行,ODAC安装时会将其路径加入path变量. 导致先搜索到ODAC,连接出现:ora-12560: TNS:protocol adapter error 将p ...

  7. 牛飞盘队Cow Frisbee Team

    老唐最近迷上了飞盘,约翰想和他一起玩,于是打算从他家的N头奶牛中选出一支队伍. 每只奶牛的能力为整数,第i头奶牛的能力为R i .飞盘队的队员数量不能少于 .大于N. 一支队伍的总能力就是所有队员能力 ...

  8. Leetcode 10. Regular Expression Matching(递归,dp)

    10. Regular Expression Matching Hard Given an input string (s) and a pattern (p), implement regular ...

  9. Kohana Minion cli 学习

    1.E:\html\tproject\framebota\platform\bootstrap.php Kohana::modules(array( 'auth' => MODPATH.'aut ...

  10. VMware 启动之后发现 eth0不存在

    启动虚拟机之后发现,eth0不存在. 问题现象: 解决办法(我): 1. 查看/etc/sysconfi/network-scripts/ifcfg-eth0的配置是否与外部网络配置一致. 例如NAT ...