Python3 内存机制
本文中交替出现 Python 的编译模式和交互模式代码块,为便于区分,带有 >>>
的 Python 代码块为交互模式,其余 Python 代码块为编译模式。
可变对象与不可变对象
可变对象 |
不可变对象 |
列表、字典、集合 |
整型、浮点型、布尔型、字符串、元组 |
简单来说,可变对象就是指在修改数据时,直接修改原来的数据对象;不可变对象则是创建一个新的对象,并且将变量的引用(相当于C++中的指针)转移到新创建的对象上。
不可变对象实例
1 2 3 4 5 6
| >>>a = 6 >>>id(a) 140725289698248 >>>a = 7 >>>id(a) 140725289698280
|
1 2 3 4 5 6 7 8 9 10 11
| >>>string = "ykx!!!" >>>new_string = string >>>id(string) 2053870338288 >>>id(new_string) 2053870338288 >>>new_string = string.replace("!","?") >>>new_string 'ykx???' >>>id(new_string) 2053827268784
|
可变对象实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| >>>tinydic = {"ykx":"大帅哥","hhy":"憨憨"} >>>new_tinydic = {"Mercedes":"cool"} >>>id(tinydic) 2053870017280 >>>id(new_tinydic) 2053870017728 >>>tinydic.update(new_tinydic) >>>tinydic {'ykx': '大帅哥', 'hhy': '憨憨', 'Mercedes': 'cool'} >>>id(tinydic) 2053870017280 >>>id(new_tinydic) 2053870017728 >>>new_tinydic["Mercedes"] = "considerable" id(new_tinydic) 2053870017728
|
深拷贝与浅拷贝
在Python中,拷贝对象时有两种方式:浅拷贝(shallow copy)和深拷贝(deep copy)。理解它们之间的区别对处理复杂的数据结构非常重要。
浅拷贝(Shallow Copy)
拷贝对象的引用。当原对象的数据改变时,拷贝的对象也会发生改变。
浅拷贝创建一个新的对象,但不会递归地复制对象中包含的所有子对象。对于包含的子对象,浅拷贝只会复制它们的引用。
可以使用 copy
模块中的 copy()
函数或对象的 copy()
方法来进行浅拷贝。
深拷贝(Deep Copy)
创建一个新的对象并将原数据存入新的对象。原对象数据改变不影响拷贝对象
深拷贝创建一个新的对象,并递归地复制所有包含的对象,形成一个独立的副本。深拷贝后的对象与原对象完全独立,修改其中一个不会影响另一个。
可以使用 copy
模块中的 deepcopy()
函数来进行深拷贝。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13
| import copy
original_list = [1, 2, [3, 4]] shallow_copied_list = copy.copy(original_list)
print(original_list) print(shallow_copied_list)
original_list[2][0] = 99
print(original_list) print(shallow_copied_list)
|
在这个例子中,修改 original_list
中的子列表也影响了 shallow_copied_list
,因为它们共享同一个子列表的引用。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13
| import copy
original_list = [1, 2, [3, 4]] deep_copied_list = copy.deepcopy(original_list)
print(original_list) print(deep_copied_list)
original_list[2][0] = 99
print(original_list) print(deep_copied_list)
|
在这个例子中,修改 original_list
中的子列表不会影响 deep_copied_list
,因为深拷贝创建了一个完全独立的副本。
值得注意的是,python3中列表默认的的.copy()方法是浅拷贝,但是remove()方法会改变深浅。
示例
1 2 3 4 5 6 7
| >>> original_list = [1, 2, [3, 4]] >>> shallow_copied_list = original_list.copy() >>> original_list[2][0] = 99 >>> original_list [1, 2, [99, 4]] >>> shallow_copied_list [1, 2, [99, 4]]
|
在这个例子中,修改 original_list
中的子列表也影响了 shallow_copied_list
,因为它们共享同一个子列表的引用。
1 2 3 4 5 6 7 8
| >>> a = ["safdf",1,2,3,5,4,8,7] >>> b = a.copy() >>> a.remove(1) >>> a ['safdf', 2, 3, 5, 4, 8, 7] >>> b ['safdf', 1, 2, 3, 5, 4, 8, 7] >>> b = a.copy()
|
在这个例子中,使用remove()方法后会再次开辟一块内存深拷贝a,a和b就不属于同一引用了。
使用 copy
模块进行浅拷贝和深拷贝
1 2 3 4 5 6 7 8
| import copy
shallow_copy = copy.copy(original_object) shallow_copied_list = original_list.copy()
deep_copy = copy.deepcopy(original_object)
|
适用场景
- 浅拷贝适用于对象层次结构较浅且只需要复制最外层的情况。
- 深拷贝适用于对象层次结构较深且需要完整独立副本的情况。
注意事项
- 浅拷贝在处理不可变对象(如整数、字符串、元组)时,行为与深拷贝相同,因为这些对象本质上不会被修改。
- 深拷贝可能会比较耗时和耗内存,特别是对于大型复杂对象。
理解浅拷贝和深拷贝的区别,以及如何在Python中正确使用它们,对于编写健壮的代码非常重要。
浅拷贝:只拷贝对象的引用
**深拷贝:**再开辟一块内存,新建立一条引用储存拷贝对象
相关库
copy
深浅拷贝举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import copy dic_mother = {"母体":"111"} dic_son = {"1":"111"}
dic_mother["子体"] = dic_son
print(f"刚刚初始化的母体字典{dic_son}") print(f"刚刚初始化的母体字典{dic_mother}")
dic_mother_shallowcopy = dic_mother dic_mother_shallowcopy["子体"]["1"] = "222" print(f"浅拷贝并修改后的的母体字典{dic_mother_shallowcopy}") print(f"子体字典{dic_son}")
dic_mother_deepcopy = copy.deepcopy(dic_mother) dic_mother_deepcopy["子体"]["1"] = "333" print(f"浅拷贝并修改后的的母体字典{dic_mother_deepcopy}") print(f"子体字典{dic_son}")
|
输出结果
1 2 3 4 5 6
| 刚刚初始化的母体字典{'1': '111'} 刚刚初始化的母体字典{'母体': '111', '子体': {'1': '111'}} 浅拷贝并修改后的的母体字典{'母体': '111', '子体': {'1': '222'}} 子体字典{'1': '222'} 浅拷贝并修改后的的母体字典{'母体': '111', '子体': {'1': '333'}} 子体字典{'1': '222'}
|
可以看出深浅拷贝copy.copy()
:深拷贝父对象(一级目录),子对象(二级目录)不拷贝,子对象是引用