当前位置: 首页 > article >正文

Python深浅拷贝

文章目录

  • 1 概述
  • 2 数据类型
    • 2.1 可变类型
    • 2.2 不可变类型
  • 3 深浅拷贝
    • 3.1 浅拷贝
    • 3.2 深拷贝
  • 4 深浅拷贝对数据类型的影响
    • 4.1 对于不可变类型的影响
    • 4.2 对于可变类型的影响
    • 4.3 总结
  • 5 实现机制
    • 5.1 copy
    • 5.2 id
  • 6 示例
    • 6.1 普通赋值
    • 6.2 浅拷贝可变类型
    • 6.3 浅拷贝不可变类型
    • 6.4 深拷贝可变类型
    • 6.5 深拷贝不可变类型
  • 7 注意事项


1 概述

在 Python 中,可变类型和不可变类型的拷贝行为有所不同。理解它们的区别对于正确使用浅拷贝和深拷贝非常重要。

2 数据类型

在Python中,从对象的内存值是否可以被修改的角度来考虑,数据类型可分为可变类型和不可变类型。

2.1 可变类型

可变类型的对象在创建后,其内存中的值可以被修改,而对象的内存地址(引用)不变。常见类型包括列表(list)字典(dict)集合 (set)

2.2 不可变类型

对象一旦创建,其内存中的值就不能被修改。如果需要“修改”不可变对象,实际上是创建了一个新对象,并将变量(引用)指向新对象的内存地址。常见类型包括字符串 (str)元组 (tuple)数值类型(整型 int、浮点型 float)布尔类型 (bool)

3 深浅拷贝

在 Python 中,从对象及其嵌套对象的复制方式的角度来考虑,拷贝可分为浅拷贝和深拷贝。

3.1 浅拷贝

浅拷贝只复制对象本身,而不复制对象内部的嵌套对象。浅拷贝后的对象和原对象共享内部的嵌套对象。

3.2 深拷贝

深拷贝会递归复制对象及其所有嵌套对象。深拷贝后的对象和原对象完全独立,互不影响。

4 深浅拷贝对数据类型的影响

4.1 对于不可变类型的影响

对于不可变类型(如字符串 (str)元组 (tuple)数值类型(整型 int、浮点型 float)等),无论是浅拷贝还是深拷贝,都不会创建新对象,而是直接引用原对象。这是因为不可变对象的值不能被修改,共享是安全的。

4.2 对于可变类型的影响

对于对于可变类型(如列表、字典、集合等),深浅拷贝的行为会有所不同:
浅拷贝:创建一个新对象,但嵌套的可变对象仍然是共享的。
深拷贝:创建一个新对象,并递归复制所有嵌套的可变对象。

4.3 总结

类型浅拷贝行为深拷贝行为
不可变类型与赋值相同,直接引用原对象(如果包含可变对象,则嵌套的可变对象共享)与赋值相同,直接引用原对象(如果包含可变对象,则嵌套的可变对象共享)
可变类型创建新对象,但嵌套的可变对象共享创建新对象,并递归复制所有嵌套的可变对象

5 实现机制

5.1 copy

在 Python 中,浅拷贝和深拷贝是通过copy模块中的copy()deepcopy()函数实现的。

浅拷贝:copy模块的copy()
深拷贝:copy模块的deepcopy()函数

5.2 id

在 Python 中,可以通过id()函数获取对象的内存地址。id() 返回一个整数,表示对象的唯一标识符(通常是对象在内存中的地址)。这个地址在对象的生命周期内是唯一的,可以用来判断两个变量是否指向同一个对象。

6 示例

6.1 普通赋值

普通赋值,内存地址都一样

# 不可变类型
num_1 = 8919
num_2 = num_1
print(f'id(num_1):{id(num_1)}')  # 2522975289840
print(f'id(num_2):{id(num_2)}')  # 2522975289840
print(f'id(8919):{id(8919)}')    # 2522975289840

# 可变类型
list_1 = ['辰南', '梦可儿', '龙舞']
list_2 = ['唤魔经', '太上忘情录', '通天动地魔功']
list_3 = [list_1, list_2]
list_4 = list_3
print(f'id(list_3):{id(list_3)}')  # 2522975191232
print(f'id(list_4):{id(list_4)}')  # 2522975191232

6.2 浅拷贝可变类型

浅拷贝只复制对象本身,而不复制对象内部的嵌套对象

import copy

list_1 = ['辰南', '梦可儿', '龙舞']
list_2 = ['唤魔经', '太上忘情录', '通天动地魔功']
list_3 = [list_1, list_2, 8919, 12]
# 浅拷贝
list_4 = copy.copy(list_3)
print(f'id(list_3):{id(list_3)}')  # 对象本身地址不一样:1579186077888
print(f'id(list_4):{id(list_4)}')  # 对象本身地址不一样:1579183616704

print(id(list_2))     # 嵌套对象地址共享:1579183315072
print(id(list_3[1]))  # 嵌套对象地址共享:1579183315072

list_2[2] = '逆乱八式'  # 嵌套对象内容修改,引用对象内容同时发生改变
print(f'list_3:{list_3}')  # list_3:[['辰南', '梦可儿', '龙舞'], ['唤魔经', '太上忘情录', '逆乱八式'], 8919, 12]
print(f'list_4:{list_4}')  # list_4:[['辰南', '梦可儿', '龙舞'], ['唤魔经', '太上忘情录', '逆乱八式'], 8919, 12]

6.3 浅拷贝不可变类型

与赋值相同,直接引用原对象(如果包含可变对象,则嵌套的可变对象共享)

import copy

tuple_1 = ('辰南', '梦可儿', '龙舞')
tuple_2 = ('唤魔经', '太上忘情录', '通天动地魔功')
tuple_3 = (tuple_1, tuple_2, 8919, 12)
tuple_4 = copy.copy(tuple_3)

print(f'id(list_3):{id(tuple_3)}')  # 地址不发生改变:1922101059136
print(f'id(list_4):{id(tuple_4)}')  # 地址不发生改变:1922101059136

print(f'id(tuple_2):{id(tuple_2)}')        # 共享地址:2341031630272
print(f'id(tuple_3[1]):{id(tuple_3[1])}')  # 共享地址:2341031630272

6.4 深拷贝可变类型

深拷贝会递归复制对象及其所有嵌套对象。深拷贝后的对象和原对象完全独立,互不影响。

import copy

list_1 = ['辰南', '梦可儿', '龙舞']
list_2 = ['唤魔经', '太上忘情录', '通天动地魔功']
list_3 = [list_1, list_2, 8919, 12]
# 浅拷贝
list_4 = copy.deepcopy(list_3)
print(f'id(list_3):{id(list_3)}')  # 对象本身地址不一样:2252152333504
print(f'id(list_4):{id(list_4)}')  # 对象本身地址不一样:2252171929023

print(id(list_2))     # 嵌套对象地址共享:2252175821184
print(id(list_3[1]))  # 嵌套对象地址共享:2252175821184

list_1[2] = '李若兰'    # 对深拷贝对象不影响
list_2[2] = '逆乱八式'  # 对深拷贝对象不影响
print(f'list_3:{list_3}')  # [['辰南', '梦可儿', '李若兰'], ['唤魔经', '太上忘情录', '逆乱八式'], 8919, 12]
print(f'list_4:{list_4}')  # [['辰南', '梦可儿', '龙舞'], ['唤魔经', '太上忘情录', '通天动地魔功'], 8919, 12] 

6.5 深拷贝不可变类型

与赋值相同,直接引用原对象(如果包含可变对象,则嵌套的可变对象共享)

import copy

tuple_1 = ('辰南', '梦可儿', '龙舞')
tuple_2 = ('唤魔经', '太上忘情录', '通天动地魔功')
tuple_3 = (tuple_1, tuple_2, 8919, 12)
tuple_4 = copy.deepcopy(tuple_3) # 深拷贝

print(f'id(list_3):{id(tuple_3)}')  # 地址不发生改变:2321897201216
print(f'id(list_4):{id(tuple_4)}')  # 地址不发生改变:2321897201216

print(f'id(tuple_2):{id(tuple_2)}')        # 共享地址:2321937124417
print(f'id(tuple_3[1]):{id(tuple_3[1])}')  # 共享地址:2321937124417

7 注意事项

  • 对于不可变类型,深浅拷贝的效果与赋值相同,因为不可变对象的值不能被修改。
  • 如果不可变对象包含可变对象(如元组中包含列表),则需要注意嵌套对象的共享问题。
  • 深拷贝可能会比较耗时,尤其是当对象嵌套层级很深或数据量很大时。

http://www.kler.cn/a/594969.html

相关文章:

  • 【QA】装饰模式在Qt中有哪些运用?
  • 服务器——报错解决:移动文件时,bash: /usr/bin/mv: Argument list too long
  • Java基础关键_027_IO流(五)
  • 软考-软件设计师-程序设计语言
  • 数据结构——顺序栈seq_stack
  • 力扣刷题——143.重排链表
  • 多数据源@DS和@Transactional踩坑之路
  • 【负载均衡系列】Nginx
  • 到底爱不爱我
  • stm32-定时器
  • GITLAB部署安装教程
  • JNI介绍
  • 算法及数据结构系列 - 二分查找
  • 游戏引擎学习第172天
  • 深度解析历年蓝桥杯算法题,助力提升编程技能
  • Saga 模式实战 Demo
  • Compose 实践与探索十五 —— 自定义触摸
  • Prometheus Exporter系列-Postgres_Exporter一键部署
  • Java 大视界 -- Java 大数据分布式计算中的通信优化与网络拓扑设计(145)
  • Python 单例模式的 5 种实现方式:深入解析与最佳实践