比较(== 和 is)
-
== :两对象的值是否相等
is:两对象的 id 是否相等(同一对象 / 同一内存地址) -
is 的速度比 == 快。
is 只比较 id
== 要重载 a.__eq__(b) 这个函数,其内部的处理通常会复杂一些,如对于列表,要遍历每个元素,判断顺序和值是否相等。
比较整数
a = 10
b = 10
print(a==b) # True
print(a is b) # True
print(id(a), id(b)) # 2006630427216, 2006630427216
a = 257
b = 257
print(a==b) # True
print(a is b) # False
print(id(a), id(b)) # 2006703506672, 2006703508176
Python 内部会对 -5 到 256 的整型维持一个数组,起到一个缓存的作用。
当创建新整数(-5 ~ 256)时,python 返回相应的引用,而不是新的内存空间,即a、b都指向同一内存地址。
当创建新整数(不是-5 ~ 256)时,python会开辟新的内存空间,即a、b都开辟新空间。
比较单例
用 is
a = None
print(a is None) # True
拷贝
浅拷贝:
- 数据类型本身的构造器,如 list()、dict()、set()、str()等等
- 切片
[:]
- copy(),包括 copy.copy() 和 list.copy()
深拷贝:
- copy.deepcopy()
注:a = b
不是拷贝,而是引用,都指向同一内存地址。
li = [1,2,3]
l2 = li
l2.append(4)
print(li) # [1, 2, 3, 4]
print(l2) # [1, 2, 3, 4]
浅拷贝
有两种情况:
- 可变对象 list、dict、set:重新分配一块内存,创建一个新的对象,里面的元素是原对象中元素的引用,因此 == 比较是True,而 is 比较都是 False。
- 不可变对象 数、tuple、str:不会分配新内存,而是返回相同元组的引用,因此 == 比较和 is 比较都是 True。
# 数据类型本身的构造器
li = [1,2,3,4]
li2 = list(li)
print(li==li2) # True
print(li is li2) # False
t = (1,2,3)
t2 = tuple(t)
print(t==t2) # True
print(t is t2) # True
s = 'abc'
s2 = str(s)
print(s==s2) # True
print(s is s2) # True
# 切片
li = [1,2,3,4]
li2 = li[:]
print(li==li2) # True
print(li is li2) # False
t = (1,2,3)
t2 = t[:]
print(t==t2) # True
print(t is t2) # True
s = 'abc'
s2 = s[:]
print(s==s2) # True
print(s is s2) # True
# copy()
import copy
li = [1,2,3,4]
li2 = copy.copy(li) # li2 = li.copy()
print(li==li2) # True
print(li is li2) # False
t = (1,2,3)
t2 = copy.copy(t)
print(t==t2) # True
print(t is t2) # True
s = 'abc'
s2 = copy.copy(s)
print(s==s2) # True
print(s is s2) # True
可变对象的浅拷贝
由于新对象中的元素是原对象中元素的引用,因此会产生问题。
l1 = [[1, 2], (30, 40)]
l2 = list(l1)
# 创建一个新列表 l2,开辟新空间,l2[i]是l1[i]的引用。
l1.append(100)
print(l1) # [[1, 2], (30, 40), 100]
print(l2) # [[1, 2], (30, 40)]
l1[0].append(3)
print(l1) # [[1, 2, 3], (30, 40), 100]
print(l2) # [[1, 2, 3], (30, 40)]
l1[1] += (50, 60) # 因为元组是不可变的,这里表示对 l1 中元组拼接,然后重新创建了一个新元组作为 l1 中的第二个元素,但l2 中没有引用新元组,引用的还是原元组。
print(l1) # [[1, 2, 3], (30, 40, 50, 60), 100]
print(l2) # [[1, 2, 3], (30, 40)]
深拷贝
新对象和原对象没有任何关联。
重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中(不是引用了)。
# copy.deepcopy()
import copy
li = [1,2,3,4]
li2 = copy.deepcopy(li)
print(li==li2) # True
print(li is li2) # False
deepcopy()中会维护一个字典,记录已经拷贝的对象及其 ID,来提高效率并防止无限递归的发生。拷贝过程中,如果字典里已经存储了将要拷贝的对象,则会从字典直接返回。