Python - Compare + Copy
== vs is
- == 比较对象之间的值是否相等,类似于 Java 中的 equals
- is 比较的是对象的身份标识是否相等,即是否为同一个对象,是否指向同一个内存地址,类似于 Java 中的 ==
- is None or is not None
- 在 Python 中,每个对象的身份标识,都能通过 id(object) 函数获得,is 比较的是对象之间的 ID 是否相等
- 类似于 Java 对象的 HashCode
- 在实际工作中,**== 更常用,一般关心的是两个变量的值,而非内部存储地址**
1 | a = 10 # allocate memory for 10 |
- a is b 为 True,仅适用于 -5 ~ 256 范围内的数字
- 出于性能考虑,Python 内部会对 -5 ~ 256 的整型维持一个数组,起到一个缓存的作用 - 与 Java 的设计类似
性能差异
is 的速度效率,一般要优于 ==
- is 操作符不能被重载,Python 无需去寻找是否有其它地方重载了该操作符,仅仅比较两个变量的 ID 而已
a == b,相当于执行
a.__eq__(b)
- Python 大部分的数据类型都会去重载
__eq__
函数,内部的处理通常会更复杂一些 - 如对于列表,
__eq__
函数会去遍历列表中的元素,比较它们的顺序和值是否相等 - 递归遍历对象的所有值,并逐一比较
- Python 大部分的数据类型都会去重载
比较结果不是一直不变的
1 | t1 = (1, 2, [3, 4]) |
浅拷贝 vs 深拷贝
常见浅拷贝 - 使用数据类型本身的构造函数
1 | l1 = [1, 2, 3] |
1 | s1 = {1, 2, 3} |
copy.copy() - 适用于任何数据类型 - 浅拷贝
1 | import copy |
对于元组,tuple() 或者切片操作符 ‘:‘ 不会创建浅拷贝,而是会返回一个指向相同元组的引用 - 与 Go Slice 有点类似
1 | t1 = (1, 2, 3) |
- 浅拷贝,即重新分配一块内存,创建一个新的对象,里面的元素是原对象中子对象的引用
- 如果原对象中的子对象是可变,可能会有副作用
1 | l1 = [[1, 2], (30, 40)] |
深拷贝 - 即重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,创建新的子对象拷贝到新对象中
新对象与原对象没有任何关联 - copy.deepcopy()
1 | import copy |
如果被拷贝对象中,存在指向自身的引用,程序容易陷入无限循环
1 | import copy |
- 程序并没有出现 stack overflow
- 原因 - deepcopy 函数会维护一个字典,记录已经拷贝的对象和其 ID
- 如果字典中已经存储了将要拷贝的对象,则直接返回
- 提高效率并防止无限递归的发生
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.