Python(十九):比较、深浅拷贝

比较(== 和 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,来提高效率并防止无限递归的发生。拷贝过程中,如果字典里已经存储了将要拷贝的对象,则会从字典直接返回。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值