- images
- results
- .gitignore
- 1.1概论.ipynb
- 1.2 环境配置.pdf
- 1.3数据类型.ipynb
- 1.4 人机交互.ipynb
- 1.5 对象与变量.ipynb
- 1.6 编码与命名规范.ipynb
- 2.1 数值类型.ipynb
- 2.2 数值类型转换.ipynb
- 2.3 数值元算.ipynb
- 2.4常用数学运算函数.ipynb
- 2.5 math 模块及其应用.ipynb
- 2.6.1 逻辑值测试.ipynb
- 2.6.2 成员运算.ipynb
- 2.6.3 比较运算.ipynb
- 2.6.4 布尔运算.ipynb
- 2.6.5 运算优先级.ipynb
- 2.ipynb
- 3.1 流程控制结构.ipynb
- 3.3.1 for 循环语句.ipynb
- 3.3.3 rang.ipynb
- 3.3.3 while 循环语句.ipynb
- 3.4 and 3.5 分支结构和条件.ipynb
- 3.6 and 3.7 .ipynb
- 3.9 异常处理.ipynb
- 4 函数和模块化编程.ipynb
- 4.1 函数的定义、调用与返回值.ipynb
- 4.2 函数的参数传递.ipynb
- 4.3 变量的作用域.ipynb
- 4.4 匿名函数.ipynb
- 4.5 递归.ipynb
- 4.6 内置函数.ipynb
- 4.7 模块化程序设计.ipynb
- 5.1 序列通用操作.ipynb
- 5.1.1 索引.ipynb
- 5.1.2 切片.ipynb
- 5.1.3 序列拼接与重复.ipynb
- 5.1.4 成员测试.ipynb
- 5.2.1 字符串的创建.ipynb
- 5.2.2 字符串常量.ipynb
- 5.2.4 字符串的遍历.ipynb
- 5.2.5 文件遍历.ipynb
- 5.2.6 字符串的处理方法.ipynb
- 5.2.7 字符串格式化.ipynb
- 5.2.8 转义字符.ipynb
- 5.3 random 模块及其应用.ipynb
- 6.1 元组.ipynb
- 6.2 列表.ipynb
- 6.2.1 列表的创建.ipynb
- 6.2.2 列表的更新.ipynb
- 6.2.3 列表的删除.ipynb
- 6.2.4 列表的排序.ipynb
- 6.2.5 列表赋值与复制.ipynb
- 6.2.6 列表推导式.ipynb
- 6.2.8 常用内置函数.ipynb
- 6.2.9 列表嵌套及其排序.ipynb
- 6.3 列表综合应用.ipynb
- 7.1.1 集合的创建.ipynb
- 7.1.2可变集合类型的操作.ipynb
- 7.1.3 成员关系.ipynb
- 7.1.4 集合关系.ipynb
- 7.1.5 集合运算.ipynb
- 7.2.1 字典创建.ipynb
- 7.2.2 获取字典值.ipynb
- 7.2.3 修改字典值.ipynb
- 7.2.4内置函数与方法.ipynb
- 7.2.5字典排序输出.ipynb
- 7.3 集合与字典的应用.ipynb
- 8 中 numpy 概述.ipynb
- 8 中panda 库.ipynb
- 8.1 文件的打开与关闭.ipynb
- 8.2 文件读写操作.ipynb
- 8.3 文件的应用.ipynb
- 8.4 numpy 文件操作.ipynb
- 8.4.2 and 3.ipynb
- 8.5.1 pandas文件读写.ipynb
- 8.5.2 and 3 and 4.ipynb
- 9.1 matplotlib 线性图.ipynb
- 9.1.5 数据文化绘图.ipynb
- 9.2 非线性图.ipynb
- 9.3 词云.ipynb
- _overview.md
- _readme.ipynb
- coding_here.ipynb
- dream.png
- score.txt
- score_total.csv
- 成绩分析综合.json
6.2.5 列表赋值与复制.ipynb @master — view markup · raw · history · blame
6.7 列表的赋值和复制¶
将一个列表ls直接赋值给另一个变量lsnew时,并不会产生新的对象,只相当于给原列表存储的位置多加了一个标签lsnew,可以同时使用ls和lsnew两个标签访问原列表。当列表ls的值发生变化时,lsnew同时发生变化。
当使用copy()方法复制或用列表切片再赋值时,相当于创建一个新对象,再拷贝数据的一个副本,称为浅复制。新对象与原列表无直接关联,对其中一个操作也不会影响另一个对象。
# 只拷贝第一层的叫浅拷贝,如元素为可变数据类型,只拷贝其首地址,可变数据类型元素值发生变化,会影响用浅拷贝创建的对象。
# 递归拷贝到底的叫深拷贝,拷贝结果完全独立于原对象
import copy
ls = [2,5,['a',[22,33],'c'],9] # 创建一个对象ls
ls1 = ls # ls对象加一个新标签,值随ls变化而变化
ls2 = ls[1:3] # 切片,得到新对象
ls3 = ls.copy() # 产生新对象
ls4 = [x for x in ls] # 列表推导式
ls5 = copy.deepcopy(ls) # 产生新对象,递归拷贝ls中所有元素,对象创建后完全独立于ls
ls.append(10) # ls 末尾增加一个元素
ls[2][1].append(44) # ls 中序号为2的元素['a',[22,33],'c']中序号为1的元素[22,33]末尾增加一个元素
print(id(ls),id(ls1),id(ls2),id(ls3),id(ls4),id(ls5))
print("ls:",ls)
print("ls1:",ls1)
print("ls2:",ls2)
print("ls3:",ls3)
print("ls4:",ls4)
print("ls5:",ls5)
由上例可以看出,ls1和ls的id值相同,表示它们指向同一序列,而ls2、ls3、ls4和ls5的id值各不相同,表明它们指向不同对象。 不同的是,ls5在创建时,递归复制了ls里所有元素,称为深复制,这种方法创建的对象完全独立于原始对象,原始对象的任何变化都不会影响到深复制创建的对象。 ls2、ls3和ls4只复制一层元素,当其中某可变数据类型元素的值发生变化时,ls2、ls3和ls4中对应元素的值也会发生变化。 与字符串一样,当列表乘一个整数n时是一种重复操作,相当于一个id的对象被复制n次。
ls = [[ ]] * 3 # ls[0]被复制3次
print(ls) # [[], [], []]
print(id(ls[0]),id(ls[1]),id(ls[2]))
# ls[0],ls[1],ls[2]id相同,是同一对象的不同标签
# 输出2438949169160 2438949169160 2438949169160
ls[0].append(3) # 列表ls[0]新增一个元素
print(ls) # [[3], [3], [3]],对象值改变,通过不同标签访问的都是修改过的值
ls[0].append(5) # 列表ls[0]新增一个元素
print(ls)
# [[3, 5], [3, 5], [3, 5]],对象值改变,通过不同标签访问的都是修改过的值

严格来说,Python 中赋值语句并不是把对象的值赋给变量名,而是在变量名和对象之间创建绑定关系,或者说给存储在数据起一个名字或加一个标签以方便重复访问。 对于自身可变(如列表)或者包含可变项(如列表做为元素)的集合对象,在程序开发时有时会需要生成其副本用于改变操作,避免改变原对象。copy 模块提供了通用的浅层 (shallow) 复制和深层 (deep)复制操作,语法如下:
copy.copy(x) # 返回 x 的浅层复制。
copy.deepcopy(x[, memo]) # 返回 x 的深层复制。
exception copy.error # 针对模块特定错误引发。
浅层复制和深层复制都会创新一个新的对象,他们之间的区别仅与复合对象 (即包含其他对象的对象,如列表或类的实例) 相关: ● 一个 浅层复制 会构造一个新的复合对象,然后(在可能的范围内)将原对象中找到的 引用 插入其中。 ● 一个 深层复制 会构造一个新的复合对象,然后递归地将原始对象中所找到的对象的 副本 插入。
import copy
ls = [1,2,'123',[4,5,(7,8,[9,10])]]
ls2 = copy.copy(ls)
ls3 = copy.deepcopy(ls)

深度复制操作通常存在两个问题, 而浅层复制操作并不存在这些问题: ● 递归对象 (直接或间接包含对自身引用的复合对象) 可能会导致递归循环。 ● 由于深层复制会复制所有内容,因此可能会过多复制(例如本应该在副本之间共享的数据)。 deepcopy() 函数通过以下操作避免这些问题: ● 保留在当前复制过程中已复制的对象的 "备忘录" (memo) 字典; ● 允许用户定义的类重载复制操作或复制的组件集合。 该模块不复制模块、方法、栈追踪(stack trace)、栈帧(stack frame)、文件、套接字、窗口、数组以及任何类似的类型。它通过不改变地返回原始对象来(浅层或深层地)“复制”函数和类;这与 pickle 模块处理这类问题的方式是相似的。 制作字典的浅层复制可以使用 dict.copy() 方法,而制作列表的浅层复制可以通过赋值整个列表的切片完成,例如:
copied_list = original_list[:]
类可以使用与控制序列化(pickling)操作相同的接口来控制复制操作,关于这些方法的描述信息可参考 pickle模块。实际上,copy 模块使用的正是从 copyreg 模块中注册的 pickle 函数。 想要给一个类定义它自己的拷贝操作实现,可以通过定义特殊方法 copy() 和 deepcopy()。 调用前者以实现浅层拷贝操作,该方法不用传入额外参数。 调用后者以实现深层拷贝操作;它应传入一个参数即 memo字典。 如果 deepcopy() 实现需要创建一个组件的深层拷贝,它应当调用 deepcopy() 函数并以该组件作为第一个参数,而将 memo 字典作为第二个参数。
# 以下两种方法都可以获得包含以3个空列表为元素的列表
lists = [[]] * 3
print(lists) # [[], [], []]
ls = [[] for i in range(3)]
print(ls) # [[], [], []]
从图中可以看到,lists的三个元素引用自同一个对象,是重复引用。而ls中的3个元素是分3次创建的3个空列表,是3个独立的对象。两个列表虽然看似相同,但包含的对象数量是不同的。

# 以下两种方法都可以获得包含以3个空列表为元素的列表
lists = [[]] * 3
lists[0].append(3)
print(lists) # [[3], [3], [3]]
# 上述代码中3个元素中由lists[0]重复得到,都引用自lists[0],是同一个对象。
# 当这个对象的改变时,引用这个对象的所有名字的值也会发生相应的变化
ls = [[] for i in range(3)]
ls[0].append(3)
ls[1].append(5)
ls[2].append(7)
print(ls) # [[3], [5], [7]]
lists中的三个空列表是同一个对象的3次引用,所以改变其中一个值的时候,3个元素的值同时发生了变化。而ls中的三个空列表是3个独立的对象,改变列表的值的时候,相互之间无影响。
# 以下两种方法都可以获得包含以3个空列表为元素的列表
lists = [[]] * 3
lists[0].append(3)
lists[1].append(6)
lists[2].append(9)
print(lists) # [[3, 6, 9], [3, 6, 9], [3, 6, 9]]
# 上述代码中3个元素中由lists[0]重复得到,都引用自lists[0],是同一个对象。
# 当这个对象的改变时,引用这个对象的所有名字的值也会发生相应的变化
ls = [[] for i in range(3)]
ls[0].append(3)
ls[1].append(5)
ls[2].append(7)
print(ls) # [[3], [5], [7]]

# 只拷贝第一层的叫浅拷贝,如元素为可变数据类型,只拷贝其首地址,可变数据类型元素值发生变化,会影响用浅拷贝创建的对象。
# 递归拷贝到底的叫深拷贝,拷贝结果完全独立于原对象
import copy
ls = [2,5,['a',[22,33],'c'],9] # 创建一个对象ls
ls1 = ls # ls对象加一个新标签,值随ls变化而变化
ls.append(10) # ls 末尾增加一个元素
print(id(ls),id(ls1))
print("ls:",ls)
print("ls1:",ls1)