Python高级编程(10):深拷贝与浅拷贝

一、深拷贝和浅拷贝概念

  • 浅拷贝重新分配一块内存创建一个新的对象,拷贝父对象,不会拷贝对象内部的子对象。
  • 深拷贝重新分配一块内存创建一个新的对象,完全拷贝父对象和子对象,新对象和原对象没有任何关联

1.1 简单来说:

  • 浅拷贝只复制某个对象的引用,而不复制对象本身,新旧对象还是共享同一块内存。
  • 深拷贝会创造一个一模一样的对象,新对象和原对象不共享内存,修改新对象不会改变原对象。

1.2 深浅拷贝优缺点:

  • 浅拷贝耗时短,占用内存空间少。
  • 深拷贝耗时长,且占用内存空间。

二、浅拷贝

2.1 只有一层数据类型,且为可变数据类型,如列表、字典。

"""
只有一层数据类型,且为可变数据类型,
浅拷贝后会创建一个新的内存地址
"""

from copy import copy

l1 = [1, 2, 3, 4]
l2 = copy(l1)

print(id(l1))  # 34653376
print(id(l2))  # 35040256

l1.append(5)
l2.append(6)
print(l1)  # [1, 2, 3, 4, 5]
print(l2)  # [1, 2, 3, 4, 6]

2.2 只有一层数据类型,且为不可变数据类型

"""
只有一层数据类型,且为不可变数据类型,
浅拷贝后内存地址不变
"""

from copy import copy

l1 = "1234"
l2 = copy(l1)

print(id(l1))  # 38998256
print(id(l2))  # 38998256

2.3 有两层数据类型,外层为可变数据类型,内层包含可变数据类型元素

"""
有两层数据类型,外层为可变数据类型,内层包含可变数据类型
浅拷贝后外层地址改变,内层地址不变
"""

from copy import copy

l1 = [1, 2, 3, 4, [100, 200]]

l2 = copy(l1)

print(id(l1))  # 40283008
print(id(l2))  # 40440768

print(id(l1[4]))  # 39306240
print(id(l2[4]))  # 39306240
                  # 内层地址不变可以减少内存地址开销

l1[4].append(300)
print(l1)  # [1, 2, 3, 4, [100, 200, 300]]
print(l2)  # [1, 2, 3, 4, [100, 200, 300]]
           # 使用浅拷贝,如果元素中存在可变类型数据,
           # 内层的子列表不会发生拷贝,所以子列表发生变化,对应拷贝后的列表也发生变化

三、深拷贝

3.1 只有一层数据类型,且为可变数据类型,如列表、字典。

"""
只有一层数据类型,且为可变数据类型,
深拷贝后会创建一个新的内存地址
"""

from copy import deepcopy

l1 = [1, 2, 3, 4]

l2 = deepcopy(l1)

print(id(l1))  # 39371840
print(id(l2))  # 40086400

l1.append(5)
l2.append(6)
print(l1)  # [1, 2, 3, 4, 5]
print(l2)  # [1, 2, 3, 4, 6]

3.2 只有一层数据类型,且为不可变数据类型

"""
只有一层数据类型,且为不可变数据类型,
深拷贝后内存地址不变
"""

from copy import deepcopy

l1 = "1234"

l2 = deepcopy(l1)

print(id(l1))  # 34544432
print(id(l2))  # 34544432

3.3 有两层数据类型,外层为可变数据类型,内层包含可变数据类型元素

"""
有两层数据类型,外层为可变数据类型,内层包含可变数据类型
深拷贝后外层地址改变,内层地址改变
"""

from copy import deepcopy

l1 = [1, 2, 3, 4, [100, 200]]

l2 = deepcopy(l1)

print(id(l1))  # 40217536
print(id(l2))  # 40375296

print(id(l1[4]))  # 39502976
print(id(l2[4]))  # 39152832
                  # 深拷贝后外层地址改变

l1[4].append(300)
print(l1)  # [1, 2, 3, 4, [100, 200, 300]]
print(l2)  # [1, 2, 3, 4, [100, 200]]
           # 使用深拷贝,如果元素中存在可变类型数据,
           # 内层的子列表也发生拷贝,子列表变化,拷贝后的列表不会变化

3.4 有两层数据类型,外层为可变数据类型,内层包含不可变数据类型元素 

"""
有两层数据类型,外层为可变数据类型,
内层不可变数据类型的元素,深拷贝不改变内层地址,
内层是可变数据类型的元素,深拷贝改变内层地址
"""

from copy import deepcopy

l1 = [1, 2, 3, [100, 200], "1121"]

l2 = deepcopy(l1)

# 外层是可变数据类型,深拷贝,外层地址改变
print(id(l1))  # 40152000
print(id(l2))  # 40301888

# 内层是可变数据类型的元素,深拷贝,该元素对应的内层地址发生改变
print(id(l1[3]))  # 39437504
print(id(l2[3]))  # 39438144

# 内层是不可变数据类型的元素,深拷贝,该元素对应的内层地址不变
print(id(l1[4]))  # 39066416
print(id(l2[4]))  # 39066416

四、深拷贝和浅拷贝总结

  • 浅拷贝只有外层是可变数据类型时,才能改变外层地址。内层地址无论是否是可变数据类型,都不会改变内层地址。所以,浅拷贝不会拷贝子列表,子列表发生变化对应的拷贝后的数据也会发生变化。
  • 深拷贝内层是可变数据类型时,内外层地址均发生改变。内层不可变数据类型的元素,深拷贝后对应元素处的内层地址不会改变。所以,深拷贝会拷贝子列表,子列表发生变化对应的拷贝后的数据不会发生变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值